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