1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/credential_management/android/third_party_credential_manager_impl.h"
#include "base/android/jni_callback.h"
#include "base/check_deref.h"
#include "base/functional/bind.h"
#include "base/notimplemented.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/ssl_status.h"
namespace credential_management {
ThirdPartyCredentialManagerImpl::ThirdPartyCredentialManagerImpl(
content::WebContents* web_contents)
: bridge_(std::make_unique<ThirdPartyCredentialManagerBridge>()),
web_contents_(CHECK_DEREF(web_contents)) {}
ThirdPartyCredentialManagerImpl::ThirdPartyCredentialManagerImpl(
base::PassKey<class ThirdPartyCredentialManagerImplTest>,
content::WebContents* web_contents,
std::unique_ptr<CredentialManagerBridge> bridge)
: bridge_(std::move(bridge)), web_contents_(CHECK_DEREF(web_contents)) {}
ThirdPartyCredentialManagerImpl::~ThirdPartyCredentialManagerImpl() = default;
void ThirdPartyCredentialManagerImpl::Store(
const password_manager::CredentialInfo& credential,
StoreCallback callback) {
// Don't store empty credentials.
if (credential.type ==
password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY) {
return;
}
std::u16string username = credential.id.value_or(u"");
std::u16string password = credential.password.value_or(u"");
bridge_->Store(username, password,
web_contents_->GetPrimaryMainFrame()
->GetLastCommittedOrigin()
.Serialize(),
std::move(callback));
}
void ThirdPartyCredentialManagerImpl::PreventSilentAccess(
PreventSilentAccessCallback callback) {
// Send acknowledge response back.
// We're currently preventing silent access for every get request by default
// in 3rd party mode so there is nothing more to do here for now.
std::move(callback).Run();
}
// This method decides if credential picker should be shown.
// Credential mediation can be silent, optional, conditional or
// required.
// Silent mediation should not show a credential picker even if there
// are multiple credentials available and return null.
// Silent mediation can't be implemented here, because the Android API
// doesn't support it. We'd have to know the amount of available credentials
// already before calling get.
// By default, the GetCredentialRequest will have optional
// mediation: if there's more than one matching credential, the system
// will show the credential picker UI to the user.
// Required mediation will show the credential picker, no matter the amount
// of choices.
// Conditional mediation allows the user to pick a credential from the
// picker or avoid selecting a credential without any user-visible error
// condition. That type of mediotion is also not supported in the Android
// API.
bool ShouldAllowAutoSelect(
password_manager::CredentialMediationRequirement mediation) {
switch (mediation) {
case password_manager::CredentialMediationRequirement::kOptional:
return true;
case password_manager::CredentialMediationRequirement::kRequired:
return false;
case password_manager::CredentialMediationRequirement::kSilent:
case password_manager::CredentialMediationRequirement::kConditional:
NOTIMPLEMENTED();
}
return false;
}
net::CertStatus ThirdPartyCredentialManagerImpl::GetMainFrameCertStatus()
const {
content::NavigationEntry* entry =
web_contents_->GetController().GetLastCommittedEntry();
if (!entry) {
return 0;
}
return entry->GetSSL().cert_status;
}
void ThirdPartyCredentialManagerImpl::Get(
password_manager::CredentialMediationRequirement mediation,
bool include_passwords,
const std::vector<GURL>& federations,
GetCallback callback) {
// Return an empty credential if the current page has SSL errors.
if (net::IsCertStatusError(GetMainFrameCertStatus())) {
std::move(callback).Run(password_manager::CredentialManagerError::SUCCESS,
password_manager::CredentialInfo());
return;
}
// Return an empty credential for incognito mode.
if (IsOffTheRecord()) {
// Callback with empty credential info.
std::move(callback).Run(password_manager::CredentialManagerError::SUCCESS,
password_manager::CredentialInfo());
return;
}
// Silent mediation is not supported because the list of origins that prevent
// silent access can't be persisted.
// Conditional mediation is only for passkeys, not for passwords that are
// currently the only supported credential type.
// Return an empty credential in these cases.
if (mediation == password_manager::CredentialMediationRequirement::kSilent ||
mediation ==
password_manager::CredentialMediationRequirement::kConditional) {
std::move(callback).Run(password_manager::CredentialManagerError::SUCCESS,
password_manager::CredentialInfo());
return;
}
bridge_->Get(ShouldAllowAutoSelect(mediation), include_passwords, federations,
web_contents_->GetPrimaryMainFrame()
->GetLastCommittedOrigin()
.Serialize(),
std::move(callback));
}
void ThirdPartyCredentialManagerImpl::ResetAfterDisconnecting() {
// There is currently nothing to do upon disconnecting for this implementation
// of CredentialManagerInterface.
}
bool ThirdPartyCredentialManagerImpl::IsOffTheRecord() const {
return web_contents_->GetBrowserContext()->IsOffTheRecord();
}
} // namespace credential_management
|