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