1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "android_webview/native/aw_contents_client_bridge.h"
6
7#include "base/android/jni_android.h"
8#include "base/android/jni_array.h"
9#include "base/android/scoped_java_ref.h"
10#include "base/bind.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/run_loop.h"
13#include "content/public/test/test_browser_thread_bundle.h"
14#include "jni/MockAwContentsClientBridge_jni.h"
15#include "net/android/net_jni_registrar.h"
16#include "net/ssl/ssl_cert_request_info.h"
17#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20
21using base::android::AttachCurrentThread;
22using base::android::ScopedJavaLocalRef;
23using net::SSLCertRequestInfo;
24using net::SSLClientCertType;
25using net::X509Certificate;
26using testing::NotNull;
27using testing::Test;
28
29namespace android_webview {
30
31namespace {
32
33// Tests the android_webview contents client bridge.
34class AwContentsClientBridgeTest : public Test {
35 public:
36  typedef AwContentsClientBridge::SelectCertificateCallback
37      SelectCertificateCallback;
38
39  AwContentsClientBridgeTest() { }
40
41  // Callback method called when a cert is selected.
42  void CertSelected(X509Certificate* cert);
43 protected:
44  virtual void SetUp();
45  void TestCertType(SSLClientCertType type, const std::string& expected_name);
46  // Create the TestBrowserThreads. Just instantiate the member variable.
47  content::TestBrowserThreadBundle thread_bundle_;
48  base::android::ScopedJavaGlobalRef<jobject> jbridge_;
49  scoped_ptr<AwContentsClientBridge> bridge_;
50  scoped_refptr<SSLCertRequestInfo> cert_request_info_;
51  X509Certificate* selected_cert_;
52  int cert_selected_callbacks_;
53  JNIEnv* env_;
54};
55
56}   // namespace
57
58void AwContentsClientBridgeTest::SetUp() {
59  env_ = AttachCurrentThread();
60  ASSERT_THAT(env_, NotNull());
61  ASSERT_TRUE(android_webview::RegisterAwContentsClientBridge(env_));
62  ASSERT_TRUE(RegisterNativesImpl(env_));
63  ASSERT_TRUE(net::android::RegisterJni(env_));
64  jbridge_.Reset(env_,
65      Java_MockAwContentsClientBridge_getAwContentsClientBridge(env_).obj());
66  bridge_.reset(new AwContentsClientBridge(env_, jbridge_.obj()));
67  selected_cert_ = NULL;
68  cert_selected_callbacks_ = 0;
69  cert_request_info_ = new net::SSLCertRequestInfo;
70}
71
72void AwContentsClientBridgeTest::CertSelected(X509Certificate* cert) {
73  selected_cert_ = cert;
74  cert_selected_callbacks_++;
75}
76
77TEST_F(AwContentsClientBridgeTest, TestClientCertKeyTypesCorrectlyEncoded) {
78  SSLClientCertType cert_types[3] = {net::CLIENT_CERT_RSA_SIGN,
79      net::CLIENT_CERT_DSS_SIGN, net::CLIENT_CERT_ECDSA_SIGN};
80  std::string expected_names[3] = {"RSA", "DSA" ,"ECDSA"};
81
82  for(int i = 0; i < 3; i++) {
83    TestCertType(cert_types[i], expected_names[i]);
84  }
85}
86
87void AwContentsClientBridgeTest::TestCertType(SSLClientCertType type,
88      const std::string& expected_name) {
89  cert_request_info_->cert_key_types.clear();
90  cert_request_info_->cert_key_types.push_back(type);
91  bridge_->SelectClientCertificate(
92      cert_request_info_.get(),
93      base::Bind(
94          &AwContentsClientBridgeTest::CertSelected,
95          base::Unretained(static_cast<AwContentsClientBridgeTest*>(this))));
96  base::RunLoop().RunUntilIdle();
97  EXPECT_EQ(0, cert_selected_callbacks_);
98  ScopedJavaLocalRef<jobjectArray> key_types =
99      Java_MockAwContentsClientBridge_getKeyTypes(env_, jbridge_.obj());
100  std::vector<std::string> vec;
101  base::android::AppendJavaStringArrayToStringVector(env_,
102                                                     key_types.obj(),
103                                                     &vec);
104  EXPECT_EQ(1u, vec.size());
105  EXPECT_EQ(expected_name, vec[0]);
106}
107
108// Verify that ProvideClientCertificateResponse works properly when the client
109// responds with a null key.
110TEST_F(AwContentsClientBridgeTest,
111    TestProvideClientCertificateResponseCallsCallbackOnNullKey) {
112  // Call SelectClientCertificate to create a callback id that mock java object
113  // can call on.
114  bridge_->SelectClientCertificate(
115    cert_request_info_.get(),
116    base::Bind(
117        &AwContentsClientBridgeTest::CertSelected,
118        base::Unretained(static_cast<AwContentsClientBridgeTest*>(this))));
119  bridge_->ProvideClientCertificateResponse(env_, jbridge_.obj(),
120      Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj()),
121      Java_MockAwContentsClientBridge_createTestCertChain(
122          env_, jbridge_.obj()).obj(),
123      NULL);
124  base::RunLoop().RunUntilIdle();
125  EXPECT_EQ(NULL, selected_cert_);
126  EXPECT_EQ(1, cert_selected_callbacks_);
127}
128
129// Verify that ProvideClientCertificateResponse calls the callback with
130// NULL parameters when private key is not provided.
131TEST_F(AwContentsClientBridgeTest,
132    TestProvideClientCertificateResponseCallsCallbackOnNullChain) {
133  // Call SelectClientCertificate to create a callback id that mock java object
134  // can call on.
135  bridge_->SelectClientCertificate(
136    cert_request_info_.get(),
137    base::Bind(
138        &AwContentsClientBridgeTest::CertSelected,
139        base::Unretained(static_cast<AwContentsClientBridgeTest*>(this))));
140  int requestId =
141    Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj());
142  bridge_->ProvideClientCertificateResponse(env_, jbridge_.obj(),
143      requestId,
144      NULL,
145      Java_MockAwContentsClientBridge_createTestPrivateKey(
146          env_, jbridge_.obj()).obj());
147  base::RunLoop().RunUntilIdle();
148  EXPECT_EQ(NULL, selected_cert_);
149  EXPECT_EQ(1, cert_selected_callbacks_);
150}
151
152}   // android_webview
153