Chromium Code Reviews| Index: android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java |
| diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java |
| index 66e4f1ec9522047bf983c2461f4f653f47352712..d8064404dafb143b682f198b5c2190fd3acfdc93 100644 |
| --- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java |
| +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java |
| @@ -6,10 +6,21 @@ package org.chromium.android_webview; |
| import android.net.http.SslCertificate; |
| import android.net.http.SslError; |
| +import android.util.Log; |
| import android.webkit.ValueCallback; |
| import org.chromium.base.CalledByNative; |
| import org.chromium.base.JNINamespace; |
| +import org.chromium.base.ThreadUtils; |
| +import org.chromium.net.AndroidPrivateKey; |
| +import org.chromium.net.DefaultAndroidKeyStore; |
| + |
| +import java.security.Principal; |
| +import java.security.PrivateKey; |
| +import java.security.cert.CertificateEncodingException; |
| +import java.security.cert.X509Certificate; |
| + |
| +import javax.security.auth.x500.X500Principal; |
| /** |
| * This class handles the JNI communication logic for the the AwContentsClient class. |
| @@ -20,14 +31,86 @@ import org.chromium.base.JNINamespace; |
| */ |
| @JNINamespace("android_webview") |
| public class AwContentsClientBridge { |
| + static final String TAG = "AwContentsClientBridge"; |
| private AwContentsClient mClient; |
| // The native peer of this object. |
| private long mNativeContentsClientBridge; |
| - public AwContentsClientBridge(AwContentsClient client) { |
| + private DefaultAndroidKeyStore mLocalKeyStore; |
| + |
| + private ClientCertLookupTable mLookupTable; |
| + |
| + // Used for mocking this class in tests. |
| + protected AwContentsClientBridge(DefaultAndroidKeyStore keyStore, |
| + ClientCertLookupTable table) { |
| + mLocalKeyStore = keyStore; |
| + mLookupTable = table; |
| + } |
| + |
| + public AwContentsClientBridge(AwContentsClient client, DefaultAndroidKeyStore keyStore, |
| + ClientCertLookupTable table) { |
| assert client != null; |
| mClient = client; |
| + mLocalKeyStore = keyStore; |
| + mLookupTable = table; |
| + } |
| + |
| + /** |
| + * Callback to communicate clientcertificaterequest back to the AwContentsClientBridge. |
| + * The public methods should be called on UI thread. |
| + */ |
| + public class ClientCertificateRequestCallback { |
| + |
| + private int mId; |
| + private String mHost; |
| + private int mPort; |
| + |
| + public ClientCertificateRequestCallback(int id, String host, int port) { |
| + mId = id; |
| + mHost = host; |
| + mPort = port; |
| + } |
| + |
| + public void proceed(PrivateKey privateKey, X509Certificate[] chain) { |
| + ThreadUtils.assertOnUiThread(); |
| + AndroidPrivateKey key = mLocalKeyStore.createKey(privateKey); |
| + |
| + if (key == null || chain == null || chain.length == 0) { |
| + Log.w(TAG, "Empty client certificate chain?"); |
| + provideResponse(null, null); |
| + return; |
| + } |
| + // Encode the certificate chain. |
| + byte[][] encodedChain = new byte[chain.length][]; |
| + try { |
| + for (int i = 0; i < chain.length; ++i) { |
| + encodedChain[i] = chain[i].getEncoded(); |
| + } |
| + } catch (CertificateEncodingException e) { |
| + Log.w(TAG, "Could not retrieve encoded certificate chain: " + e); |
| + provideResponse(null, null); |
| + return; |
| + } |
| + mLookupTable.allow(mHost, mPort, key, encodedChain); |
| + provideResponse(key, encodedChain); |
| + } |
| + |
| + public void ignore() { |
| + ThreadUtils.assertOnUiThread(); |
| + provideResponse(null, null); |
| + } |
| + |
| + public void cancel() { |
| + ThreadUtils.assertOnUiThread(); |
| + mLookupTable.deny(mHost, mPort); |
| + provideResponse(null, null); |
| + } |
| + |
| + private void provideResponse(AndroidPrivateKey androidKey, byte[][] certChain) { |
| + nativeProvideClientCertificateResponse(mNativeContentsClientBridge, mId, |
| + certChain, androidKey); |
| + } |
| } |
| // Used by the native peer to set/reset a weak ref to the native peer. |
| @@ -66,6 +149,44 @@ public class AwContentsClientBridge { |
| nativeProceedSslError(mNativeContentsClientBridge, proceed, id); |
| } |
| + // Intentionally not private for testing the native peer of this class. |
| + @CalledByNative |
| + protected void selectClientCertificate(final int id, final String[] keyTypes, |
| + byte[][] encodedPrincipals, final String host, final int port) { |
| + ClientCertLookupTable.Cert cert = mLookupTable.getCertData(host, port); |
| + if (mLookupTable.isDenied(host, port)) { |
| + nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id, |
| + null, null); |
| + return; |
| + } |
| + if (cert != null) { |
| + nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id, |
| + cert.certChain, cert.privateKey); |
| + return; |
| + } |
| + // Build the list of principals from encoded versions. |
| + Principal[] principals = null; |
| + if (encodedPrincipals.length > 0) { |
| + principals = new X500Principal[encodedPrincipals.length]; |
| + try { |
| + for (int n = 0; n < encodedPrincipals.length; n++) { |
| + principals[n] = new X500Principal(encodedPrincipals[n]); |
| + } |
| + } catch (IllegalArgumentException e) { |
|
boliu
2014/04/21 16:56:45
My second sentence was not complete.
Can you also
sgurun-gerrit only
2014/04/21 23:53:29
Done.
|
| + Log.w(TAG, "Exception while decoding issuers list: " + e); |
| + nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id, |
| + null, null); |
| + return; |
| + } |
| + } |
| + |
| + final ClientCertificateRequestCallback callback = |
| + new ClientCertificateRequestCallback(id, host, port); |
| + // We've taken the ownership of the native ssl request object. |
| + mClient.onReceivedClientCertRequest(callback, keyTypes, principals, host, port); |
| + return; |
| + } |
| + |
| @CalledByNative |
| private void handleJsAlert(String url, String message, int id) { |
| JsResultHandler handler = new JsResultHandler(this, id); |
| @@ -110,6 +231,8 @@ public class AwContentsClientBridge { |
| //-------------------------------------------------------------------------------------------- |
| private native void nativeProceedSslError(long nativeAwContentsClientBridge, boolean proceed, |
| int id); |
| + private native void nativeProvideClientCertificateResponse(long nativeAwContentsClientBridge, |
| + int id, byte[][] certChain, AndroidPrivateKey androidKey); |
| private native void nativeConfirmJsResult(long nativeAwContentsClientBridge, int id, |
| String prompt); |