Implement OnSelectClientCertificate (fixes #3789)
This commit is contained in:
parent
030272fe4c
commit
fc20e76d3b
|
@ -33,7 +33,7 @@
|
|||
// by hand. See the translator.README.txt file in the tools directory for
|
||||
// more information.
|
||||
//
|
||||
// $hash=db7cfb76483d6ab73eba74deaefafa7700ad1988$
|
||||
// $hash=cf3b97164ac99d564ebcd30f927e1331949acbe5$
|
||||
//
|
||||
|
||||
#ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_HANDLER_CAPI_H_
|
||||
|
@ -194,16 +194,19 @@ typedef struct _cef_request_handler_t {
|
|||
|
||||
///
|
||||
/// Called on the UI thread when a client certificate is being requested for
|
||||
/// authentication. Return false (0) to use the default behavior and
|
||||
/// automatically select the first certificate available. Return true (1) and
|
||||
/// call cef_select_client_certificate_callback_t::Select either in this
|
||||
/// function or at a later time to select a certificate. Do not call Select or
|
||||
/// call it with NULL to continue without using any certificate. |isProxy|
|
||||
/// indicates whether the host is an HTTPS proxy or the origin server. |host|
|
||||
/// and |port| contains the hostname and port of the SSL server.
|
||||
/// |certificates| is the list of certificates to choose from; this list has
|
||||
/// already been pruned by Chromium so that it only contains certificates from
|
||||
/// issuers that the server trusts.
|
||||
/// authentication. Return false (0) to use the default behavior. If the
|
||||
/// |certificates| list is not NULL the default behavior will be to display a
|
||||
/// dialog for certificate selection. If the |certificates| list is NULL then
|
||||
/// the default behavior will be not to show a dialog and it will continue
|
||||
/// without using any certificate. Return true (1) and call
|
||||
/// cef_select_client_certificate_callback_t::Select either in this function
|
||||
/// or at a later time to select a certificate. Do not call Select or call it
|
||||
/// with NULL to continue without using any certificate. |isProxy| indicates
|
||||
/// whether the host is an HTTPS proxy or the origin server. |host| and |port|
|
||||
/// contains the hostname and port of the SSL server. |certificates| is the
|
||||
/// list of certificates to choose from; this list has already been pruned by
|
||||
/// Chromium so that it only contains certificates from issuers that the
|
||||
/// server trusts.
|
||||
///
|
||||
int(CEF_CALLBACK* on_select_client_certificate)(
|
||||
struct _cef_request_handler_t* self,
|
||||
|
|
|
@ -192,8 +192,11 @@ class CefRequestHandler : public virtual CefBaseRefCounted {
|
|||
|
||||
///
|
||||
/// Called on the UI thread when a client certificate is being requested for
|
||||
/// authentication. Return false to use the default behavior and automatically
|
||||
/// select the first certificate available. Return true and call
|
||||
/// authentication. Return false to use the default behavior. If the
|
||||
/// |certificates| list is not empty the default behavior will be to display a
|
||||
/// dialog for certificate selection. If the |certificates| list is empty then
|
||||
/// the default behavior will be not to show a dialog and it will continue
|
||||
/// without using any certificate. Return true and call
|
||||
/// CefSelectClientCertificateCallback::Select either in this method or at a
|
||||
/// later time to select a certificate. Do not call Select or call it with
|
||||
/// NULL to continue without using any certificate. |isProxy| indicates
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "cef/libcef/browser/net_service/resource_request_handler_wrapper.h"
|
||||
#include "cef/libcef/browser/prefs/browser_prefs.h"
|
||||
#include "cef/libcef/browser/prefs/renderer_prefs.h"
|
||||
#include "cef/libcef/browser/x509_certificate_impl.h"
|
||||
#include "cef/libcef/common/app_manager.h"
|
||||
#include "cef/libcef/common/cef_switches.h"
|
||||
#include "cef/libcef/common/command_line_impl.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "components/performance_manager/embedder/performance_manager_registry.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
#include "content/public/browser/navigation_throttle.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
|
@ -39,6 +41,8 @@
|
|||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/weak_document_ptr.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
#include "net/ssl/ssl_private_key.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
|
||||
|
||||
|
@ -48,6 +52,82 @@
|
|||
|
||||
namespace {
|
||||
|
||||
class CefSelectClientCertificateCallbackImpl
|
||||
: public CefSelectClientCertificateCallback {
|
||||
public:
|
||||
explicit CefSelectClientCertificateCallbackImpl(
|
||||
std::unique_ptr<content::ClientCertificateDelegate> delegate)
|
||||
: delegate_(std::move(delegate)) {}
|
||||
|
||||
CefSelectClientCertificateCallbackImpl(
|
||||
const CefSelectClientCertificateCallbackImpl&) = delete;
|
||||
CefSelectClientCertificateCallbackImpl& operator=(
|
||||
const CefSelectClientCertificateCallbackImpl&) = delete;
|
||||
|
||||
~CefSelectClientCertificateCallbackImpl() override {
|
||||
// If Select has not been called, call it with NULL to continue without any
|
||||
// client certificate.
|
||||
RunNow(std::move(delegate_), nullptr);
|
||||
}
|
||||
|
||||
void Select(CefRefPtr<CefX509Certificate> cert) override {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(
|
||||
CEF_UIT,
|
||||
base::BindOnce(&CefSelectClientCertificateCallbackImpl::Select, this,
|
||||
cert));
|
||||
} else {
|
||||
RunNow(std::move(delegate_), cert);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<content::ClientCertificateDelegate>
|
||||
DisconnectDelegate() {
|
||||
CEF_REQUIRE_UIT();
|
||||
return std::move(delegate_);
|
||||
}
|
||||
|
||||
private:
|
||||
static void RunNow(
|
||||
std::unique_ptr<content::ClientCertificateDelegate> delegate,
|
||||
CefRefPtr<CefX509Certificate> cert) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
if (delegate) {
|
||||
if (cert) {
|
||||
CefX509CertificateImpl* certImpl =
|
||||
static_cast<CefX509CertificateImpl*>(cert.get());
|
||||
certImpl->AcquirePrivateKey(base::BindOnce(
|
||||
&CefSelectClientCertificateCallbackImpl::RunWithPrivateKey,
|
||||
std::move(delegate), cert));
|
||||
return;
|
||||
}
|
||||
|
||||
delegate->ContinueWithCertificate(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void RunWithPrivateKey(
|
||||
std::unique_ptr<content::ClientCertificateDelegate> delegate,
|
||||
CefRefPtr<CefX509Certificate> cert,
|
||||
scoped_refptr<net::SSLPrivateKey> key) {
|
||||
CEF_REQUIRE_UIT();
|
||||
DCHECK(cert);
|
||||
|
||||
if (key) {
|
||||
CefX509CertificateImpl* certImpl =
|
||||
static_cast<CefX509CertificateImpl*>(cert.get());
|
||||
delegate->ContinueWithCertificate(certImpl->GetInternalCertObject(), key);
|
||||
} else {
|
||||
delegate->ContinueWithCertificate(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<content::ClientCertificateDelegate> delegate_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefSelectClientCertificateCallbackImpl);
|
||||
};
|
||||
|
||||
void HandleExternalProtocolHelper(
|
||||
ChromeContentBrowserClientCef* self,
|
||||
content::WebContents::Getter web_contents_getter,
|
||||
|
@ -201,6 +281,64 @@ void ChromeContentBrowserClientCef::AllowCertificateError(
|
|||
strict_enforcement, std::move(returned_callback));
|
||||
}
|
||||
|
||||
base::OnceClosure ChromeContentBrowserClientCef::SelectClientCertificate(
|
||||
content::BrowserContext* browser_context,
|
||||
int process_id,
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
net::ClientCertIdentityList client_certs,
|
||||
std::unique_ptr<content::ClientCertificateDelegate> delegate) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
CefRefPtr<CefRequestHandler> handler;
|
||||
CefRefPtr<CefBrowserHostBase> browser =
|
||||
CefBrowserHostBase::GetBrowserForContents(web_contents);
|
||||
if (browser) {
|
||||
if (auto client = browser->GetClient()) {
|
||||
handler = client->GetRequestHandler();
|
||||
}
|
||||
}
|
||||
|
||||
if (!handler) {
|
||||
return ChromeContentBrowserClient::SelectClientCertificate(
|
||||
browser_context, process_id, web_contents, cert_request_info,
|
||||
std::move(client_certs), std::move(delegate));
|
||||
}
|
||||
|
||||
CefRequestHandler::X509CertificateList certs;
|
||||
for (auto& client_cert : client_certs) {
|
||||
certs.push_back(new CefX509CertificateImpl(std::move(client_cert)));
|
||||
}
|
||||
|
||||
CefRefPtr<CefSelectClientCertificateCallbackImpl> callbackImpl(
|
||||
new CefSelectClientCertificateCallbackImpl(std::move(delegate)));
|
||||
|
||||
bool handled = handler->OnSelectClientCertificate(
|
||||
browser.get(), cert_request_info->is_proxy,
|
||||
cert_request_info->host_and_port.host(),
|
||||
cert_request_info->host_and_port.port(), certs, callbackImpl.get());
|
||||
|
||||
if (!handled) {
|
||||
delegate = callbackImpl->DisconnectDelegate();
|
||||
if (delegate) {
|
||||
client_certs.clear();
|
||||
for (auto& cert : certs) {
|
||||
CefX509CertificateImpl* certImpl =
|
||||
static_cast<CefX509CertificateImpl*>(cert.get());
|
||||
client_certs.push_back(certImpl->DisconnectIdentity());
|
||||
}
|
||||
return ChromeContentBrowserClient::SelectClientCertificate(
|
||||
browser_context, process_id, web_contents, cert_request_info,
|
||||
std::move(client_certs), std::move(delegate));
|
||||
} else {
|
||||
LOG(ERROR) << "Should return true from OnSelectClientCertificate when "
|
||||
"executing the callback";
|
||||
}
|
||||
}
|
||||
|
||||
return base::OnceClosure();
|
||||
}
|
||||
|
||||
bool ChromeContentBrowserClientCef::CanCreateWindow(
|
||||
content::RenderFrameHost* opener,
|
||||
const GURL& opener_url,
|
||||
|
|
|
@ -43,6 +43,13 @@ class ChromeContentBrowserClientCef : public ChromeContentBrowserClient {
|
|||
bool strict_enforcement,
|
||||
base::OnceCallback<void(content::CertificateRequestResultType)> callback)
|
||||
override;
|
||||
base::OnceClosure SelectClientCertificate(
|
||||
content::BrowserContext* browser_context,
|
||||
int process_id,
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
net::ClientCertIdentityList client_certs,
|
||||
std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
|
||||
bool CanCreateWindow(content::RenderFrameHost* opener,
|
||||
const GURL& opener_url,
|
||||
const GURL& opener_top_level_frame_url,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "cef/libcef/browser/x509_cert_principal_impl.h"
|
||||
#include "cef/libcef/common/time_util.h"
|
||||
#include "net/cert/x509_util.h"
|
||||
#include "net/ssl/ssl_private_key.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -27,6 +28,10 @@ CefRefPtr<CefBinaryValue> EncodeCertificate(const CRYPTO_BUFFER* cert_buffer,
|
|||
|
||||
} // namespace
|
||||
|
||||
CefX509CertificateImpl::CefX509CertificateImpl(
|
||||
std::unique_ptr<net::ClientCertIdentity> identity)
|
||||
: identity_(std::move(identity)), cert_(identity_->certificate()) {}
|
||||
|
||||
CefX509CertificateImpl::CefX509CertificateImpl(
|
||||
scoped_refptr<net::X509Certificate> cert)
|
||||
: cert_(cert) {}
|
||||
|
@ -94,6 +99,21 @@ size_t CefX509CertificateImpl::GetIssuerChainSize() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CefX509CertificateImpl::AcquirePrivateKey(
|
||||
base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
|
||||
private_key_callback) {
|
||||
if (identity_) {
|
||||
identity_->AcquirePrivateKey(std::move(private_key_callback));
|
||||
} else {
|
||||
std::move(private_key_callback).Run(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<net::ClientCertIdentity>
|
||||
CefX509CertificateImpl::DisconnectIdentity() {
|
||||
return std::move(identity_);
|
||||
}
|
||||
|
||||
void CefX509CertificateImpl::GetEncodedIssuerChain(
|
||||
CefX509Certificate::IssuerChainBinaryList& chain,
|
||||
bool der) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "cef/include/cef_x509_certificate.h"
|
||||
#include "net/cert/x509_certificate.h"
|
||||
#include "net/ssl/client_cert_identity.h"
|
||||
|
||||
// CefX509Certificate implementation
|
||||
class CefX509CertificateImpl : public CefX509Certificate {
|
||||
|
@ -19,6 +20,9 @@ class CefX509CertificateImpl : public CefX509Certificate {
|
|||
CefX509CertificateImpl(const CefX509CertificateImpl&) = delete;
|
||||
CefX509CertificateImpl& operator=(const CefX509CertificateImpl&) = delete;
|
||||
|
||||
explicit CefX509CertificateImpl(
|
||||
std::unique_ptr<net::ClientCertIdentity> identity);
|
||||
|
||||
// CefX509Certificate methods.
|
||||
CefRefPtr<CefX509CertPrincipal> GetSubject() override;
|
||||
CefRefPtr<CefX509CertPrincipal> GetIssuer() override;
|
||||
|
@ -32,10 +36,16 @@ class CefX509CertificateImpl : public CefX509Certificate {
|
|||
void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) override;
|
||||
|
||||
scoped_refptr<net::X509Certificate> GetInternalCertObject() { return cert_; }
|
||||
void AcquirePrivateKey(
|
||||
base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
|
||||
private_key_callback);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<net::ClientCertIdentity> DisconnectIdentity();
|
||||
|
||||
private:
|
||||
void GetEncodedIssuerChain(IssuerChainBinaryList& chain, bool der);
|
||||
|
||||
std::unique_ptr<net::ClientCertIdentity> identity_;
|
||||
scoped_refptr<net::X509Certificate> cert_;
|
||||
IssuerChainBinaryList pem_encoded_issuer_chain_;
|
||||
IssuerChainBinaryList der_encoded_issuer_chain_;
|
||||
|
|
Loading…
Reference in New Issue