Commit 30f27028 authored by Steven Valdez's avatar Steven Valdez Committed by Commit Bot

Adding queueing for client certs.

Change-Id: I0f2e85a6fc14c4a3968594f627ea3696d50d55ff
Reviewed-on: https://chromium-review.googlesource.com/1058012Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarDavid Benjamin <davidben@chromium.org>
Commit-Queue: Steven Valdez <svaldez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#566016}
parent 2a3d3ce8
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/containers/queue.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "chrome/browser/ssl/ssl_client_certificate_selector.h" #include "chrome/browser/ssl/ssl_client_certificate_selector.h"
...@@ -35,16 +36,78 @@ namespace chrome { ...@@ -35,16 +36,78 @@ namespace chrome {
namespace { namespace {
void StartClientCertificateRequest( class SSLClientCertPendingRequests;
const net::SSLCertRequestInfo* cert_request_info,
ui::WindowAndroid* window, const char kSSLClientCertPendingRequests[] = "SSLClientCertPendingRequests";
std::unique_ptr<content::ClientCertificateDelegate> delegate) {
class ClientCertRequest {
public:
ClientCertRequest(
base::WeakPtr<SSLClientCertPendingRequests> pending_requests,
const scoped_refptr<net::SSLCertRequestInfo>& cert_request_info,
std::unique_ptr<content::ClientCertificateDelegate> delegate)
: pending_requests_(pending_requests),
cert_request_info_(cert_request_info),
delegate_(std::move(delegate)) {}
~ClientCertRequest() {}
void CertificateSelected(scoped_refptr<net::X509Certificate> cert,
scoped_refptr<net::SSLPrivateKey> key);
net::SSLCertRequestInfo* cert_request_info() const {
return cert_request_info_.get();
}
private:
base::WeakPtr<SSLClientCertPendingRequests> pending_requests_;
scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
std::unique_ptr<content::ClientCertificateDelegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(ClientCertRequest);
};
class SSLClientCertPendingRequests : public base::SupportsUserData::Data {
public:
explicit SSLClientCertPendingRequests(content::WebContents* web_contents)
: web_contents_(web_contents), weak_factory_(this) {}
~SSLClientCertPendingRequests() override {}
void AddRequest(std::unique_ptr<ClientCertRequest> request);
void RequestComplete(net::SSLCertRequestInfo* info,
scoped_refptr<net::X509Certificate> cert,
scoped_refptr<net::SSLPrivateKey> key);
base::WeakPtr<SSLClientCertPendingRequests> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
void PumpRequests();
bool active_request_ = false;
base::queue<std::unique_ptr<ClientCertRequest>> pending_requests_;
content::WebContents* web_contents_;
base::WeakPtrFactory<SSLClientCertPendingRequests> weak_factory_;
};
static void StartClientCertificateRequest(
std::unique_ptr<ClientCertRequest> request,
content::WebContents* web_contents) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
ui::WindowAndroid* window = ViewAndroidHelper::FromWebContents(web_contents)
->GetViewAndroid()
->GetWindowAndroid();
DCHECK(window);
// Build the |key_types| JNI parameter, as a String[] // Build the |key_types| JNI parameter, as a String[]
std::vector<std::string> key_types; std::vector<std::string> key_types;
for (size_t n = 0; n < cert_request_info->cert_key_types.size(); ++n) { for (size_t n = 0; n < request->cert_request_info()->cert_key_types.size();
switch (cert_request_info->cert_key_types[n]) { ++n) {
switch (request->cert_request_info()->cert_key_types[n]) {
case net::CLIENT_CERT_RSA_SIGN: case net::CLIENT_CERT_RSA_SIGN:
key_types.push_back("RSA"); key_types.push_back("RSA");
break; break;
...@@ -68,7 +131,7 @@ void StartClientCertificateRequest( ...@@ -68,7 +131,7 @@ void StartClientCertificateRequest(
// Build the |encoded_principals| JNI parameter, as a byte[][] // Build the |encoded_principals| JNI parameter, as a byte[][]
ScopedJavaLocalRef<jobjectArray> principals_ref = ScopedJavaLocalRef<jobjectArray> principals_ref =
base::android::ToJavaArrayOfByteArray( base::android::ToJavaArrayOfByteArray(
env, cert_request_info->cert_authorities); env, request->cert_request_info()->cert_authorities);
if (principals_ref.is_null()) { if (principals_ref.is_null()) {
LOG(ERROR) << "Could not create principals array (byte[][])"; LOG(ERROR) << "Could not create principals array (byte[][])";
return; return;
...@@ -78,21 +141,72 @@ void StartClientCertificateRequest( ...@@ -78,21 +141,72 @@ void StartClientCertificateRequest(
// a jint. // a jint.
ScopedJavaLocalRef<jstring> host_name_ref = ScopedJavaLocalRef<jstring> host_name_ref =
base::android::ConvertUTF8ToJavaString( base::android::ConvertUTF8ToJavaString(
env, cert_request_info->host_and_port.host()); env, request->cert_request_info()->host_and_port.host());
// Pass the address of the delegate through to Java. // Pass the address of the delegate through to Java.
jlong request_id = reinterpret_cast<intptr_t>(delegate.get()); jlong request_id = reinterpret_cast<intptr_t>(request.get());
if (!chrome::android:: if (!chrome::android::
Java_SSLClientCertificateRequest_selectClientCertificate( Java_SSLClientCertificateRequest_selectClientCertificate(
env, request_id, window->GetJavaObject(), key_types_ref, env, request_id, window->GetJavaObject(), key_types_ref,
principals_ref, host_name_ref, principals_ref, host_name_ref,
cert_request_info->host_and_port.port())) { request->cert_request_info()->host_and_port.port())) {
return; return;
} }
// Ownership was transferred to Java. // Ownership was transferred to Java.
ignore_result(delegate.release()); ignore_result(request.release());
}
void SSLClientCertPendingRequests::AddRequest(
std::unique_ptr<ClientCertRequest> request) {
pending_requests_.push(std::move(request));
PumpRequests();
}
void SSLClientCertPendingRequests::RequestComplete(
net::SSLCertRequestInfo* info,
scoped_refptr<net::X509Certificate> cert,
scoped_refptr<net::SSLPrivateKey> key) {
active_request_ = false;
std::string host_and_port = info->host_and_port.ToString();
base::queue<std::unique_ptr<ClientCertRequest>> new_pending_requests;
while (!pending_requests_.empty()) {
std::unique_ptr<ClientCertRequest> next =
std::move(pending_requests_.front());
pending_requests_.pop();
if (host_and_port == next->cert_request_info()->host_and_port.ToString()) {
next->CertificateSelected(cert, key);
} else {
new_pending_requests.push(std::move(next));
}
}
pending_requests_.swap(new_pending_requests);
PumpRequests();
}
void SSLClientCertPendingRequests::PumpRequests() {
if (active_request_ || pending_requests_.empty()) {
return;
}
active_request_ = true;
std::unique_ptr<ClientCertRequest> next =
std::move(pending_requests_.front());
pending_requests_.pop();
StartClientCertificateRequest(std::move(next), web_contents_);
}
void ClientCertRequest::CertificateSelected(
scoped_refptr<net::X509Certificate> cert,
scoped_refptr<net::SSLPrivateKey> key) {
delegate_->ContinueWithCertificate(cert, key);
if (pending_requests_) {
pending_requests_->RequestComplete(cert_request_info(), cert, key);
}
} }
} // namespace } // namespace
...@@ -118,13 +232,13 @@ static void JNI_SSLClientCertificateRequest_OnSystemRequestCompletion( ...@@ -118,13 +232,13 @@ static void JNI_SSLClientCertificateRequest_OnSystemRequestCompletion(
const JavaParamRef<jobject>& private_key_ref) { const JavaParamRef<jobject>& private_key_ref) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Take back ownership of the delegate object. // Take back ownership of the request object.
std::unique_ptr<content::ClientCertificateDelegate> delegate( std::unique_ptr<ClientCertRequest> request(
reinterpret_cast<content::ClientCertificateDelegate*>(request_id)); reinterpret_cast<ClientCertRequest*>(request_id));
if (encoded_chain_ref == NULL || private_key_ref == NULL) { if (encoded_chain_ref == NULL || private_key_ref == NULL) {
LOG(ERROR) << "No client certificate selected"; LOG(ERROR) << "No client certificate selected";
delegate->ContinueWithCertificate(nullptr, nullptr); request->CertificateSelected(nullptr, nullptr);
return; return;
} }
...@@ -155,8 +269,7 @@ static void JNI_SSLClientCertificateRequest_OnSystemRequestCompletion( ...@@ -155,8 +269,7 @@ static void JNI_SSLClientCertificateRequest_OnSystemRequestCompletion(
return; return;
} }
delegate->ContinueWithCertificate(std::move(client_cert), request->CertificateSelected(std::move(client_cert), std::move(private_key));
std::move(private_key));
} }
static void NotifyClientCertificatesChanged() { static void NotifyClientCertificatesChanged() {
...@@ -192,11 +305,18 @@ void ShowSSLClientCertificateSelector( ...@@ -192,11 +305,18 @@ void ShowSSLClientCertificateSelector(
return; return;
} }
ui::WindowAndroid* window = ViewAndroidHelper::FromWebContents(contents) SSLClientCertPendingRequests* active_requests =
->GetViewAndroid()->GetWindowAndroid(); static_cast<SSLClientCertPendingRequests*>(
DCHECK(window); contents->GetUserData(&kSSLClientCertPendingRequests));
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
StartClientCertificateRequest(cert_request_info, window, std::move(delegate)); if (active_requests == nullptr) {
active_requests = new SSLClientCertPendingRequests(contents);
contents->SetUserData(&kSSLClientCertPendingRequests,
base::WrapUnique(active_requests));
}
active_requests->AddRequest(std::make_unique<ClientCertRequest>(
active_requests->GetWeakPtr(), cert_request_info, std::move(delegate)));
} }
} // namespace chrome } // namespace chrome
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment