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.
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"
29 using ::testing::Mock
;
30 using ::testing::StrictMock
;
31 using content::BrowserThread
;
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.
37 class SSLClientCertificateSelectorTest
: public InProcessBrowserTest
{
39 SSLClientCertificateSelectorTest()
40 : io_loop_finished_event_(false, false),
45 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE
{
46 base::FilePath certs_dir
= net::GetTestCertsDirectory();
48 mit_davidben_cert_
= net::ImportCertFromFile(certs_dir
, "mit.davidben.der");
49 ASSERT_NE(static_cast<net::X509Certificate
*>(NULL
), mit_davidben_cert_
);
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_
);
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_
);
62 virtual void SetUpOnMainThread() OVERRIDE
{
63 url_request_context_getter_
= browser()->profile()->GetRequestContext();
65 BrowserThread::PostTask(
66 BrowserThread::IO
, FROM_HERE
,
67 base::Bind(&SSLClientCertificateSelectorTest::SetUpOnIOThread
, this));
69 io_loop_finished_event_
.Wait();
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
,
81 EXPECT_EQ(mit_davidben_cert_
.get(), selector_
->GetSelectedCert());
84 virtual void SetUpOnIOThread() {
85 url_request_
= MakeURLRequest(url_request_context_getter_
).release();
87 auth_requestor_
= new StrictMock
<SSLClientAuthRequestorMock
>(
91 io_loop_finished_event_
.Signal();
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));
101 io_loop_finished_event_
.Wait();
103 auth_requestor_
= NULL
;
106 virtual void CleanUpOnIOThread() {
109 io_loop_finished_event_
.Signal();
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
, NULL
);
119 base::WaitableEvent io_loop_finished_event_
;
121 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter_
;
122 net::URLRequest
* url_request_
;
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_
;
132 class SSLClientCertificateSelectorMultiTabTest
133 : public SSLClientCertificateSelectorTest
{
135 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE
{
136 SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
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_
);
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_
);
149 virtual void SetUpOnMainThread() OVERRIDE
{
150 // Also calls SetUpOnIOThread.
151 SSLClientCertificateSelectorTest::SetUpOnMainThread();
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));
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
,
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
,
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());
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();
185 auth_requestor_1_
= new StrictMock
<SSLClientAuthRequestorMock
>(
187 cert_request_info_1_
);
188 auth_requestor_2_
= new StrictMock
<SSLClientAuthRequestorMock
>(
190 cert_request_info_2_
);
192 SSLClientCertificateSelectorTest::SetUpOnIOThread();
195 virtual void CleanUpOnMainThread() OVERRIDE
{
196 auth_requestor_2_
= NULL
;
197 auth_requestor_1_
= NULL
;
198 SSLClientCertificateSelectorTest::CleanUpOnMainThread();
201 virtual void CleanUpOnIOThread() OVERRIDE
{
202 delete url_request_1_
;
203 delete url_request_2_
;
204 SSLClientCertificateSelectorTest::CleanUpOnIOThread();
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_
;
218 class SSLClientCertificateSelectorMultiProfileTest
219 : public SSLClientCertificateSelectorTest
{
221 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE
{
222 SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
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_
);
230 virtual void SetUpOnMainThread() OVERRIDE
{
231 browser_1_
= CreateIncognitoBrowser();
232 url_request_context_getter_1_
= browser_1_
->profile()->GetRequestContext();
234 // Also calls SetUpOnIOThread.
235 SSLClientCertificateSelectorTest::SetUpOnMainThread();
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
,
245 EXPECT_EQ(mit_davidben_cert_
.get(), selector_1_
->GetSelectedCert());
248 virtual void SetUpOnIOThread() OVERRIDE
{
249 url_request_1_
= MakeURLRequest(url_request_context_getter_1_
).release();
251 auth_requestor_1_
= new StrictMock
<SSLClientAuthRequestorMock
>(
253 cert_request_info_1_
);
255 SSLClientCertificateSelectorTest::SetUpOnIOThread();
258 virtual void CleanUpOnMainThread() OVERRIDE
{
259 auth_requestor_1_
= NULL
;
260 SSLClientCertificateSelectorTest::CleanUpOnMainThread();
263 virtual void CleanUpOnIOThread() OVERRIDE
{
264 delete url_request_1_
;
265 SSLClientCertificateSelectorTest::CleanUpOnIOThread();
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_
;
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
281 #define MAYBE_SelectNone SelectNone
285 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorTest
, MAYBE_SelectNone
) {
286 EXPECT_CALL(*auth_requestor_
, CertificateSelected(NULL
));
288 // Let the mock get checked on destruction.
291 // http://crbug.com/121007
292 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorTest
, DISABLED_Escape
) {
293 EXPECT_CALL(*auth_requestor_
, CertificateSelected(NULL
));
295 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
296 browser(), ui::VKEY_ESCAPE
, false, false, false, false));
298 Mock::VerifyAndClear(auth_requestor_
.get());
301 // Flaky, http://crbug.com/103534 .
302 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorTest
,
303 DISABLED_SelectDefault
) {
304 EXPECT_CALL(*auth_requestor_
, CertificateSelected(mit_davidben_cert_
.get()));
306 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
307 browser(), ui::VKEY_RETURN
, false, false, false, false));
309 Mock::VerifyAndClear(auth_requestor_
.get());
312 // http://crbug.com/121007
313 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiTabTest
,
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
));
321 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
322 browser(), ui::VKEY_ESCAPE
, false, false, false, false));
324 Mock::VerifyAndClear(auth_requestor_
.get());
325 Mock::VerifyAndClear(auth_requestor_1_
.get());
326 Mock::VerifyAndClear(auth_requestor_2_
.get());
328 // Now let the default selection for auth_requestor_ mock get checked on
330 EXPECT_CALL(*auth_requestor_
, CertificateSelected(NULL
));
333 // http://crbug.com/121007
334 IN_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()));
344 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
345 browser(), ui::VKEY_DOWN
, false, false, false, false));
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());
351 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
352 browser(), ui::VKEY_RETURN
, false, false, false, false));
354 Mock::VerifyAndClear(auth_requestor_
.get());
355 Mock::VerifyAndClear(auth_requestor_1_
.get());
356 Mock::VerifyAndClear(auth_requestor_2_
.get());
358 // Now let the default selection for auth_requestor_ mock get checked on
360 EXPECT_CALL(*auth_requestor_
, CertificateSelected(NULL
));
363 // http://crbug.com/103529
364 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest
,
366 EXPECT_CALL(*auth_requestor_1_
, CertificateSelected(NULL
));
368 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
369 browser_1_
, ui::VKEY_ESCAPE
, false, false, false, false));
371 Mock::VerifyAndClear(auth_requestor_
.get());
372 Mock::VerifyAndClear(auth_requestor_1_
.get());
374 // Now let the default selection for auth_requestor_ mock get checked on
376 EXPECT_CALL(*auth_requestor_
, CertificateSelected(NULL
));
379 // http://crbug.com/103534
380 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest
,
381 DISABLED_SelectDefault
) {
382 EXPECT_CALL(*auth_requestor_1_
,
383 CertificateSelected(mit_davidben_cert_
.get()));
385 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
386 browser_1_
, ui::VKEY_RETURN
, false, false, false, false));
388 Mock::VerifyAndClear(auth_requestor_
.get());
389 Mock::VerifyAndClear(auth_requestor_1_
.get());
391 // Now let the default selection for auth_requestor_ mock get checked on
393 EXPECT_CALL(*auth_requestor_
, CertificateSelected(NULL
));