1// Copyright (c) 2012 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 "base/bind.h"
6#include "base/files/file_path.h"
7#include "base/synchronization/waitable_event.h"
8#include "chrome/browser/profiles/profile.h"
9#include "chrome/browser/ssl/ssl_client_auth_requestor_mock.h"
10#include "chrome/browser/ui/browser.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/browser/ui/views/ssl_client_certificate_selector.h"
13#include "chrome/test/base/in_process_browser_test.h"
14#include "chrome/test/base/interactive_test_utils.h"
15#include "chrome/test/base/ui_test_utils.h"
16#include "content/public/browser/web_contents.h"
17#include "content/public/test/browser_test_utils.h"
18#include "net/base/test_data_directory.h"
19#include "net/cert/x509_certificate.h"
20#include "net/http/http_transaction_factory.h"
21#include "net/ssl/ssl_cert_request_info.h"
22#include "net/test/cert_test_util.h"
23#include "net/url_request/url_request.h"
24#include "net/url_request/url_request_context.h"
25#include "net/url_request/url_request_context_getter.h"
26#include "testing/gtest/include/gtest/gtest.h"
27
28using ::testing::Mock;
29using ::testing::StrictMock;
30using content::BrowserThread;
31
32// We don't have a way to do end-to-end SSL client auth testing, so this test
33// creates a certificate selector_ manually with a mocked
34// SSLClientAuthHandler.
35
36class SSLClientCertificateSelectorTest : public InProcessBrowserTest {
37 public:
38  SSLClientCertificateSelectorTest() : io_loop_finished_event_(false, false) {
39  }
40
41  virtual void SetUpInProcessBrowserTestFixture() {
42    base::FilePath certs_dir = net::GetTestCertsDirectory();
43
44    mit_davidben_cert_ = net::ImportCertFromFile(certs_dir, "mit.davidben.der");
45    ASSERT_NE(static_cast<net::X509Certificate*>(NULL), mit_davidben_cert_);
46
47    foaf_me_chromium_test_cert_ = net::ImportCertFromFile(
48        certs_dir, "foaf.me.chromium-test-cert.der");
49    ASSERT_NE(static_cast<net::X509Certificate*>(NULL),
50              foaf_me_chromium_test_cert_);
51
52    cert_request_info_ = new net::SSLCertRequestInfo;
53    cert_request_info_->host_and_port = "foo:123";
54    cert_request_info_->client_certs.push_back(mit_davidben_cert_);
55    cert_request_info_->client_certs.push_back(foaf_me_chromium_test_cert_);
56  }
57
58  virtual void SetUpOnMainThread() {
59    url_request_context_getter_ = browser()->profile()->GetRequestContext();
60
61    BrowserThread::PostTask(
62        BrowserThread::IO, FROM_HERE,
63        base::Bind(&SSLClientCertificateSelectorTest::SetUpOnIOThread, this));
64
65    io_loop_finished_event_.Wait();
66
67    content::WaitForLoadStop(
68        browser()->tab_strip_model()->GetActiveWebContents());
69    selector_ = new SSLClientCertificateSelector(
70        browser()->tab_strip_model()->GetActiveWebContents(),
71        auth_requestor_->http_network_session_,
72        auth_requestor_->cert_request_info_,
73        base::Bind(&SSLClientAuthRequestorMock::CertificateSelected,
74                   auth_requestor_));
75    selector_->Init();
76
77    EXPECT_EQ(mit_davidben_cert_.get(), selector_->GetSelectedCert());
78  }
79
80  virtual void SetUpOnIOThread() {
81    url_request_ = MakeURLRequest(url_request_context_getter_);
82
83    auth_requestor_ = new StrictMock<SSLClientAuthRequestorMock>(
84        url_request_,
85        cert_request_info_);
86
87    io_loop_finished_event_.Signal();
88  }
89
90  // Have to release our reference to the auth handler during the test to allow
91  // it to be destroyed while the Browser and its IO thread still exist.
92  virtual void CleanUpOnMainThread() {
93    BrowserThread::PostTask(
94        BrowserThread::IO, FROM_HERE,
95        base::Bind(&SSLClientCertificateSelectorTest::CleanUpOnIOThread, this));
96
97    io_loop_finished_event_.Wait();
98
99    auth_requestor_ = NULL;
100  }
101
102  virtual void CleanUpOnIOThread() {
103    delete url_request_;
104
105    io_loop_finished_event_.Signal();
106  }
107
108 protected:
109  net::URLRequest* MakeURLRequest(
110      net::URLRequestContextGetter* context_getter) {
111    net::URLRequest* request =
112        context_getter->GetURLRequestContext()->CreateRequest(
113            GURL("https://example"), NULL);
114    return request;
115  }
116
117  base::WaitableEvent io_loop_finished_event_;
118
119  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
120  net::URLRequest* url_request_;
121
122  scoped_refptr<net::X509Certificate> mit_davidben_cert_;
123  scoped_refptr<net::X509Certificate> foaf_me_chromium_test_cert_;
124  scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
125  scoped_refptr<StrictMock<SSLClientAuthRequestorMock> > auth_requestor_;
126  // The selector will be deleted when a cert is selected or the tab is closed.
127  SSLClientCertificateSelector* selector_;
128};
129
130class SSLClientCertificateSelectorMultiTabTest
131    : public SSLClientCertificateSelectorTest {
132 public:
133  virtual void SetUpInProcessBrowserTestFixture() {
134    SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
135
136    cert_request_info_1_ = new net::SSLCertRequestInfo;
137    cert_request_info_1_->host_and_port = "bar:123";
138    cert_request_info_1_->client_certs.push_back(mit_davidben_cert_);
139    cert_request_info_1_->client_certs.push_back(foaf_me_chromium_test_cert_);
140
141    cert_request_info_2_ = new net::SSLCertRequestInfo;
142    cert_request_info_2_->host_and_port = "bar:123";
143    cert_request_info_2_->client_certs.push_back(mit_davidben_cert_);
144    cert_request_info_2_->client_certs.push_back(foaf_me_chromium_test_cert_);
145  }
146
147  virtual void SetUpOnMainThread() {
148    // Also calls SetUpOnIOThread.
149    SSLClientCertificateSelectorTest::SetUpOnMainThread();
150
151    AddTabAtIndex(1, GURL("about:blank"), content::PAGE_TRANSITION_LINK);
152    AddTabAtIndex(2, GURL("about:blank"), content::PAGE_TRANSITION_LINK);
153    ASSERT_TRUE(NULL != browser()->tab_strip_model()->GetWebContentsAt(0));
154    ASSERT_TRUE(NULL != browser()->tab_strip_model()->GetWebContentsAt(1));
155    ASSERT_TRUE(NULL != browser()->tab_strip_model()->GetWebContentsAt(2));
156    content::WaitForLoadStop(browser()->tab_strip_model()->GetWebContentsAt(1));
157    content::WaitForLoadStop(browser()->tab_strip_model()->GetWebContentsAt(2));
158
159    selector_1_ = new SSLClientCertificateSelector(
160        browser()->tab_strip_model()->GetWebContentsAt(1),
161        auth_requestor_1_->http_network_session_,
162        auth_requestor_1_->cert_request_info_,
163        base::Bind(&SSLClientAuthRequestorMock::CertificateSelected,
164                   auth_requestor_1_));
165    selector_1_->Init();
166    selector_2_ = new SSLClientCertificateSelector(
167        browser()->tab_strip_model()->GetWebContentsAt(2),
168        auth_requestor_2_->http_network_session_,
169        auth_requestor_2_->cert_request_info_,
170        base::Bind(&SSLClientAuthRequestorMock::CertificateSelected,
171                   auth_requestor_2_));
172    selector_2_->Init();
173
174    EXPECT_EQ(2, browser()->tab_strip_model()->active_index());
175    EXPECT_EQ(mit_davidben_cert_.get(), selector_1_->GetSelectedCert());
176    EXPECT_EQ(mit_davidben_cert_.get(), selector_2_->GetSelectedCert());
177  }
178
179  virtual void SetUpOnIOThread() {
180    url_request_1_ = MakeURLRequest(url_request_context_getter_);
181    url_request_2_ = MakeURLRequest(url_request_context_getter_);
182
183    auth_requestor_1_ = new StrictMock<SSLClientAuthRequestorMock>(
184        url_request_1_,
185        cert_request_info_1_);
186    auth_requestor_2_ = new StrictMock<SSLClientAuthRequestorMock>(
187        url_request_2_,
188        cert_request_info_2_);
189
190    SSLClientCertificateSelectorTest::SetUpOnIOThread();
191  }
192
193  virtual void CleanUpOnMainThread() {
194    auth_requestor_2_ = NULL;
195    auth_requestor_1_ = NULL;
196    SSLClientCertificateSelectorTest::CleanUpOnMainThread();
197  }
198
199  virtual void CleanUpOnIOThread() {
200    delete url_request_1_;
201    delete url_request_2_;
202    SSLClientCertificateSelectorTest::CleanUpOnIOThread();
203  }
204
205 protected:
206  net::URLRequest* url_request_1_;
207  net::URLRequest* url_request_2_;
208  scoped_refptr<net::SSLCertRequestInfo> cert_request_info_1_;
209  scoped_refptr<net::SSLCertRequestInfo> cert_request_info_2_;
210  scoped_refptr<StrictMock<SSLClientAuthRequestorMock> > auth_requestor_1_;
211  scoped_refptr<StrictMock<SSLClientAuthRequestorMock> > auth_requestor_2_;
212  SSLClientCertificateSelector* selector_1_;
213  SSLClientCertificateSelector* selector_2_;
214};
215
216class SSLClientCertificateSelectorMultiProfileTest
217    : public SSLClientCertificateSelectorTest {
218 public:
219  virtual void SetUpInProcessBrowserTestFixture() {
220    SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
221
222    cert_request_info_1_ = new net::SSLCertRequestInfo;
223    cert_request_info_1_->host_and_port = "foo:123";
224    cert_request_info_1_->client_certs.push_back(mit_davidben_cert_);
225    cert_request_info_1_->client_certs.push_back(foaf_me_chromium_test_cert_);
226  }
227
228  virtual void SetUpOnMainThread() {
229    browser_1_ = CreateIncognitoBrowser();
230    url_request_context_getter_1_ = browser_1_->profile()->GetRequestContext();
231
232    // Also calls SetUpOnIOThread.
233    SSLClientCertificateSelectorTest::SetUpOnMainThread();
234
235    selector_1_ = new SSLClientCertificateSelector(
236        browser_1_->tab_strip_model()->GetActiveWebContents(),
237        auth_requestor_1_->http_network_session_,
238        auth_requestor_1_->cert_request_info_,
239        base::Bind(&SSLClientAuthRequestorMock::CertificateSelected,
240                   auth_requestor_1_));
241    selector_1_->Init();
242
243    EXPECT_EQ(mit_davidben_cert_.get(), selector_1_->GetSelectedCert());
244  }
245
246  virtual void SetUpOnIOThread() {
247    url_request_1_ = MakeURLRequest(url_request_context_getter_1_);
248
249    auth_requestor_1_ = new StrictMock<SSLClientAuthRequestorMock>(
250        url_request_1_,
251        cert_request_info_1_);
252
253    SSLClientCertificateSelectorTest::SetUpOnIOThread();
254  }
255
256  virtual void CleanUpOnMainThread() {
257    auth_requestor_1_ = NULL;
258    SSLClientCertificateSelectorTest::CleanUpOnMainThread();
259  }
260
261  virtual void CleanUpOnIOThread() {
262    delete url_request_1_;
263    SSLClientCertificateSelectorTest::CleanUpOnIOThread();
264  }
265
266 protected:
267  Browser* browser_1_;
268  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_1_;
269  net::URLRequest* url_request_1_;
270  scoped_refptr<net::SSLCertRequestInfo> cert_request_info_1_;
271  scoped_refptr<StrictMock<SSLClientAuthRequestorMock> > auth_requestor_1_;
272  SSLClientCertificateSelector* selector_1_;
273};
274
275IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorTest, SelectNone) {
276  EXPECT_CALL(*auth_requestor_, CertificateSelected(NULL));
277
278  // Let the mock get checked on destruction.
279}
280
281// http://crbug.com/121007
282IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorTest, DISABLED_Escape) {
283  EXPECT_CALL(*auth_requestor_, CertificateSelected(NULL));
284
285  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
286      browser(), ui::VKEY_ESCAPE, false, false, false, false));
287
288  Mock::VerifyAndClear(auth_requestor_.get());
289}
290
291// Flaky, http://crbug.com/103534 .
292IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorTest,
293                       DISABLED_SelectDefault) {
294  EXPECT_CALL(*auth_requestor_, CertificateSelected(mit_davidben_cert_.get()));
295
296  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
297      browser(), ui::VKEY_RETURN, false, false, false, false));
298
299  Mock::VerifyAndClear(auth_requestor_.get());
300}
301
302// http://crbug.com/121007
303IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiTabTest,
304                       DISABLED_Escape) {
305  // auth_requestor_1_ should get selected automatically by the
306  // SSLClientAuthObserver when selector_2_ is accepted, since both 1 & 2 have
307  // the same host:port.
308  EXPECT_CALL(*auth_requestor_1_, CertificateSelected(NULL));
309  EXPECT_CALL(*auth_requestor_2_, CertificateSelected(NULL));
310
311  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
312      browser(), ui::VKEY_ESCAPE, false, false, false, false));
313
314  Mock::VerifyAndClear(auth_requestor_.get());
315  Mock::VerifyAndClear(auth_requestor_1_.get());
316  Mock::VerifyAndClear(auth_requestor_2_.get());
317
318  // Now let the default selection for auth_requestor_ mock get checked on
319  // destruction.
320  EXPECT_CALL(*auth_requestor_, CertificateSelected(NULL));
321}
322
323// http://crbug.com/121007
324IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiTabTest,
325                       DISABLED_SelectSecond) {
326  // auth_requestor_1_ should get selected automatically by the
327  // SSLClientAuthObserver when selector_2_ is accepted, since both 1 & 2 have
328  // the same host:port.
329  EXPECT_CALL(*auth_requestor_1_,
330              CertificateSelected(foaf_me_chromium_test_cert_.get()));
331  EXPECT_CALL(*auth_requestor_2_,
332              CertificateSelected(foaf_me_chromium_test_cert_.get()));
333
334  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
335      browser(), ui::VKEY_DOWN, false, false, false, false));
336
337  EXPECT_EQ(mit_davidben_cert_.get(), selector_->GetSelectedCert());
338  EXPECT_EQ(mit_davidben_cert_.get(), selector_1_->GetSelectedCert());
339  EXPECT_EQ(foaf_me_chromium_test_cert_.get(), selector_2_->GetSelectedCert());
340
341  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
342      browser(), ui::VKEY_RETURN, false, false, false, false));
343
344  Mock::VerifyAndClear(auth_requestor_.get());
345  Mock::VerifyAndClear(auth_requestor_1_.get());
346  Mock::VerifyAndClear(auth_requestor_2_.get());
347
348  // Now let the default selection for auth_requestor_ mock get checked on
349  // destruction.
350  EXPECT_CALL(*auth_requestor_, CertificateSelected(NULL));
351}
352
353// http://crbug.com/103529
354IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest,
355                       DISABLED_Escape) {
356  EXPECT_CALL(*auth_requestor_1_, CertificateSelected(NULL));
357
358  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
359      browser_1_, ui::VKEY_ESCAPE, false, false, false, false));
360
361  Mock::VerifyAndClear(auth_requestor_.get());
362  Mock::VerifyAndClear(auth_requestor_1_.get());
363
364  // Now let the default selection for auth_requestor_ mock get checked on
365  // destruction.
366  EXPECT_CALL(*auth_requestor_, CertificateSelected(NULL));
367}
368
369// http://crbug.com/103534
370IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest,
371                       DISABLED_SelectDefault) {
372  EXPECT_CALL(*auth_requestor_1_,
373              CertificateSelected(mit_davidben_cert_.get()));
374
375  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
376      browser_1_, ui::VKEY_RETURN, false, false, false, false));
377
378  Mock::VerifyAndClear(auth_requestor_.get());
379  Mock::VerifyAndClear(auth_requestor_1_.get());
380
381  // Now let the default selection for auth_requestor_ mock get checked on
382  // destruction.
383  EXPECT_CALL(*auth_requestor_, CertificateSelected(NULL));
384}
385