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