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 "chrome/browser/ui/website_settings/website_settings.h" 6 7#include "base/at_exit.h" 8#include "base/message_loop/message_loop.h" 9#include "base/strings/string16.h" 10#include "base/strings/utf_string_conversions.h" 11#include "chrome/browser/content_settings/host_content_settings_map.h" 12#include "chrome/browser/infobars/infobar_service.h" 13#include "chrome/browser/ui/website_settings/website_settings_ui.h" 14#include "chrome/test/base/chrome_render_view_host_test_harness.h" 15#include "chrome/test/base/testing_profile.h" 16#include "components/content_settings/core/common/content_settings.h" 17#include "components/content_settings/core/common/content_settings_types.h" 18#include "components/infobars/core/infobar.h" 19#include "content/public/browser/cert_store.h" 20#include "content/public/common/ssl_status.h" 21#include "net/cert/cert_status_flags.h" 22#include "net/cert/x509_certificate.h" 23#include "net/ssl/ssl_connection_status_flags.h" 24#include "net/test/test_certificate_data.h" 25#include "testing/gmock/include/gmock/gmock.h" 26#include "testing/gtest/include/gtest/gtest.h" 27 28using content::SSLStatus; 29using testing::_; 30using testing::AnyNumber; 31using testing::Return; 32using testing::SetArgPointee; 33 34namespace { 35 36// SSL cipher suite like specified in RFC5246 Appendix A.5. "The Cipher Suite". 37// Without the CR_ prefix, this clashes with the OS X 10.8 headers. 38int CR_TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3D; 39 40int SetSSLVersion(int connection_status, int version) { 41 // Clear SSL version bits (Bits 20, 21 and 22). 42 connection_status &= 43 ~(net::SSL_CONNECTION_VERSION_MASK << net::SSL_CONNECTION_VERSION_SHIFT); 44 int bitmask = version << net::SSL_CONNECTION_VERSION_SHIFT; 45 return bitmask | connection_status; 46} 47 48int SetSSLCipherSuite(int connection_status, int cipher_suite) { 49 // Clear cipher suite bits (the 16 lowest bits). 50 connection_status &= ~net::SSL_CONNECTION_CIPHERSUITE_MASK; 51 return cipher_suite | connection_status; 52} 53 54class MockCertStore : public content::CertStore { 55 public: 56 virtual ~MockCertStore() {} 57 MOCK_METHOD2(StoreCert, int(net::X509Certificate*, int)); 58 MOCK_METHOD2(RetrieveCert, bool(int, scoped_refptr<net::X509Certificate>*)); 59}; 60 61class MockWebsiteSettingsUI : public WebsiteSettingsUI { 62 public: 63 virtual ~MockWebsiteSettingsUI() {} 64 MOCK_METHOD1(SetCookieInfo, void(const CookieInfoList& cookie_info_list)); 65 MOCK_METHOD1(SetPermissionInfo, 66 void(const PermissionInfoList& permission_info_list)); 67 MOCK_METHOD1(SetIdentityInfo, void(const IdentityInfo& identity_info)); 68 MOCK_METHOD1(SetFirstVisit, void(const base::string16& first_visit)); 69 MOCK_METHOD1(SetSelectedTab, void(TabId tab_id)); 70}; 71 72class WebsiteSettingsTest : public ChromeRenderViewHostTestHarness { 73 public: 74 WebsiteSettingsTest() : cert_id_(0), url_("http://www.example.com") {} 75 76 virtual ~WebsiteSettingsTest() { 77 } 78 79 virtual void SetUp() { 80 ChromeRenderViewHostTestHarness::SetUp(); 81 // Setup stub SSLStatus. 82 ssl_.security_style = content::SECURITY_STYLE_UNAUTHENTICATED; 83 84 // Create the certificate. 85 cert_id_ = 1; 86 base::Time start_date = base::Time::Now(); 87 base::Time expiration_date = base::Time::FromInternalValue( 88 start_date.ToInternalValue() + base::Time::kMicrosecondsPerWeek); 89 cert_ = new net::X509Certificate("subject", 90 "issuer", 91 start_date, 92 expiration_date); 93 94 TabSpecificContentSettings::CreateForWebContents(web_contents()); 95 InfoBarService::CreateForWebContents(web_contents()); 96 97 // Setup the mock cert store. 98 EXPECT_CALL(cert_store_, RetrieveCert(cert_id_, _) ) 99 .Times(AnyNumber()) 100 .WillRepeatedly(DoAll(SetArgPointee<1>(cert_), Return(true))); 101 102 // Setup mock ui. 103 mock_ui_.reset(new MockWebsiteSettingsUI()); 104 } 105 106 virtual void TearDown() { 107 ASSERT_TRUE(website_settings_.get()) 108 << "No WebsiteSettings instance created."; 109 RenderViewHostTestHarness::TearDown(); 110 website_settings_.reset(); 111 } 112 113 void SetDefaultUIExpectations(MockWebsiteSettingsUI* mock_ui) { 114 // During creation |WebsiteSettings| makes the following calls to the ui. 115 EXPECT_CALL(*mock_ui, SetPermissionInfo(_)); 116 EXPECT_CALL(*mock_ui, SetIdentityInfo(_)); 117 EXPECT_CALL(*mock_ui, SetCookieInfo(_)); 118 EXPECT_CALL(*mock_ui, SetFirstVisit(base::string16())); 119 } 120 121 const GURL& url() const { return url_; } 122 MockCertStore* cert_store() { return &cert_store_; } 123 int cert_id() { return cert_id_; } 124 MockWebsiteSettingsUI* mock_ui() { return mock_ui_.get(); } 125 const SSLStatus& ssl() { return ssl_; } 126 TabSpecificContentSettings* tab_specific_content_settings() { 127 return TabSpecificContentSettings::FromWebContents(web_contents()); 128 } 129 InfoBarService* infobar_service() { 130 return InfoBarService::FromWebContents(web_contents()); 131 } 132 133 WebsiteSettings* website_settings() { 134 if (!website_settings_.get()) { 135 website_settings_.reset(new WebsiteSettings( 136 mock_ui(), profile(), tab_specific_content_settings(), 137 infobar_service(), url(), ssl(), cert_store())); 138 } 139 return website_settings_.get(); 140 } 141 142 SSLStatus ssl_; 143 144 private: 145 scoped_ptr<WebsiteSettings> website_settings_; 146 scoped_ptr<MockWebsiteSettingsUI> mock_ui_; 147 int cert_id_; 148 scoped_refptr<net::X509Certificate> cert_; 149 MockCertStore cert_store_; 150 GURL url_; 151}; 152 153} // namespace 154 155TEST_F(WebsiteSettingsTest, OnPermissionsChanged) { 156 // Setup site permissions. 157 HostContentSettingsMap* content_settings = 158 profile()->GetHostContentSettingsMap(); 159 ContentSetting setting = content_settings->GetContentSetting( 160 url(), url(), CONTENT_SETTINGS_TYPE_POPUPS, std::string()); 161 EXPECT_EQ(setting, CONTENT_SETTING_BLOCK); 162 setting = content_settings->GetContentSetting( 163 url(), url(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string()); 164 EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); 165 setting = content_settings->GetContentSetting( 166 url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()); 167 EXPECT_EQ(setting, CONTENT_SETTING_ASK); 168 setting = content_settings->GetContentSetting( 169 url(), url(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()); 170 EXPECT_EQ(setting, CONTENT_SETTING_ASK); 171 setting = content_settings->GetContentSetting( 172 url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string()); 173 EXPECT_EQ(setting, CONTENT_SETTING_ASK); 174 setting = content_settings->GetContentSetting( 175 url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string()); 176 EXPECT_EQ(setting, CONTENT_SETTING_ASK); 177 178 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); 179 EXPECT_CALL(*mock_ui(), SetCookieInfo(_)); 180 EXPECT_CALL(*mock_ui(), SetFirstVisit(base::string16())); 181 182 // SetPermissionInfo() is called once initially, and then again every time 183 // OnSitePermissionChanged() is called. 184// TODO(markusheintz): This is a temporary hack to fix issue: http://crbug.com/144203. 185#if defined(OS_MACOSX) 186 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(6); 187#else 188 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(1); 189#endif 190 EXPECT_CALL(*mock_ui(), SetSelectedTab( 191 WebsiteSettingsUI::TAB_ID_PERMISSIONS)); 192 193 // Execute code under tests. 194 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_POPUPS, 195 CONTENT_SETTING_ALLOW); 196 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_PLUGINS, 197 CONTENT_SETTING_BLOCK); 198 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_GEOLOCATION, 199 CONTENT_SETTING_ALLOW); 200 website_settings()->OnSitePermissionChanged( 201 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW); 202 website_settings()->OnSitePermissionChanged( 203 CONTENT_SETTINGS_TYPE_MEDIASTREAM, CONTENT_SETTING_ALLOW); 204 205 // Verify that the site permissions were changed correctly. 206 setting = content_settings->GetContentSetting( 207 url(), url(), CONTENT_SETTINGS_TYPE_POPUPS, std::string()); 208 EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); 209 setting = content_settings->GetContentSetting( 210 url(), url(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string()); 211 EXPECT_EQ(setting, CONTENT_SETTING_BLOCK); 212 setting = content_settings->GetContentSetting( 213 url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()); 214 EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); 215 setting = content_settings->GetContentSetting( 216 url(), url(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()); 217 EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); 218 setting = content_settings->GetContentSetting( 219 url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string()); 220 EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); 221 setting = content_settings->GetContentSetting( 222 url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string()); 223 EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); 224} 225 226TEST_F(WebsiteSettingsTest, OnSiteDataAccessed) { 227 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)); 228 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); 229 EXPECT_CALL(*mock_ui(), SetFirstVisit(base::string16())); 230 EXPECT_CALL(*mock_ui(), SetCookieInfo(_)).Times(2); 231 EXPECT_CALL(*mock_ui(), SetSelectedTab( 232 WebsiteSettingsUI::TAB_ID_PERMISSIONS)); 233 234 website_settings()->OnSiteDataAccessed(); 235} 236 237TEST_F(WebsiteSettingsTest, HTTPConnection) { 238 SetDefaultUIExpectations(mock_ui()); 239 EXPECT_CALL(*mock_ui(), SetSelectedTab( 240 WebsiteSettingsUI::TAB_ID_PERMISSIONS)); 241 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED, 242 website_settings()->site_connection_status()); 243 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_NO_CERT, 244 website_settings()->site_identity_status()); 245 EXPECT_EQ(base::string16(), website_settings()->organization_name()); 246} 247 248TEST_F(WebsiteSettingsTest, HTTPSConnection) { 249 ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED; 250 ssl_.cert_id = cert_id(); 251 ssl_.cert_status = 0; 252 ssl_.security_bits = 81; // No error if > 80. 253 int status = 0; 254 status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); 255 status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); 256 ssl_.connection_status = status; 257 258 SetDefaultUIExpectations(mock_ui()); 259 EXPECT_CALL(*mock_ui(), SetSelectedTab( 260 WebsiteSettingsUI::TAB_ID_PERMISSIONS)); 261 262 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, 263 website_settings()->site_connection_status()); 264 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT, 265 website_settings()->site_identity_status()); 266 EXPECT_EQ(base::string16(), website_settings()->organization_name()); 267} 268 269TEST_F(WebsiteSettingsTest, HTTPSMixedContent) { 270 ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED; 271 ssl_.cert_id = cert_id(); 272 ssl_.cert_status = 0; 273 ssl_.security_bits = 81; // No error if > 80. 274 ssl_.content_status = SSLStatus::DISPLAYED_INSECURE_CONTENT; 275 int status = 0; 276 status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); 277 status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); 278 ssl_.connection_status = status; 279 280 SetDefaultUIExpectations(mock_ui()); 281 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); 282 283 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_MIXED_CONTENT, 284 website_settings()->site_connection_status()); 285 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT, 286 website_settings()->site_identity_status()); 287 EXPECT_EQ(base::string16(), website_settings()->organization_name()); 288} 289 290TEST_F(WebsiteSettingsTest, HTTPSEVCert) { 291 scoped_refptr<net::X509Certificate> ev_cert = 292 net::X509Certificate::CreateFromBytes( 293 reinterpret_cast<const char*>(google_der), 294 sizeof(google_der)); 295 int ev_cert_id = 1; 296 EXPECT_CALL(*cert_store(), RetrieveCert(ev_cert_id, _)).WillRepeatedly( 297 DoAll(SetArgPointee<1>(ev_cert), Return(true))); 298 299 ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED; 300 ssl_.cert_id = ev_cert_id; 301 ssl_.cert_status = net::CERT_STATUS_IS_EV; 302 ssl_.security_bits = 81; // No error if > 80. 303 ssl_.content_status = SSLStatus::DISPLAYED_INSECURE_CONTENT; 304 int status = 0; 305 status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); 306 status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); 307 ssl_.connection_status = status; 308 309 SetDefaultUIExpectations(mock_ui()); 310 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); 311 312 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_MIXED_CONTENT, 313 website_settings()->site_connection_status()); 314 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT, 315 website_settings()->site_identity_status()); 316 EXPECT_EQ(base::UTF8ToUTF16("Google Inc"), 317 website_settings()->organization_name()); 318} 319 320TEST_F(WebsiteSettingsTest, HTTPSRevocationError) { 321 ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED; 322 ssl_.cert_id = cert_id(); 323 ssl_.cert_status = net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; 324 ssl_.security_bits = 81; // No error if > 80. 325 int status = 0; 326 status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); 327 status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); 328 ssl_.connection_status = status; 329 330 SetDefaultUIExpectations(mock_ui()); 331 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); 332 333 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, 334 website_settings()->site_connection_status()); 335 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN, 336 website_settings()->site_identity_status()); 337 EXPECT_EQ(base::string16(), website_settings()->organization_name()); 338} 339 340TEST_F(WebsiteSettingsTest, HTTPSConnectionError) { 341 ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED; 342 ssl_.cert_id = cert_id(); 343 ssl_.cert_status = 0; 344 ssl_.security_bits = 1; 345 int status = 0; 346 status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); 347 status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); 348 ssl_.connection_status = status; 349 350 SetDefaultUIExpectations(mock_ui()); 351 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); 352 353 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR, 354 website_settings()->site_connection_status()); 355 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT, 356 website_settings()->site_identity_status()); 357 EXPECT_EQ(base::string16(), website_settings()->organization_name()); 358} 359 360TEST_F(WebsiteSettingsTest, NoInfoBar) { 361 SetDefaultUIExpectations(mock_ui()); 362 EXPECT_CALL(*mock_ui(), SetSelectedTab( 363 WebsiteSettingsUI::TAB_ID_PERMISSIONS)); 364 EXPECT_EQ(0u, infobar_service()->infobar_count()); 365 website_settings()->OnUIClosing(); 366 EXPECT_EQ(0u, infobar_service()->infobar_count()); 367} 368 369TEST_F(WebsiteSettingsTest, ShowInfoBar) { 370 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); 371 EXPECT_CALL(*mock_ui(), SetCookieInfo(_)); 372 EXPECT_CALL(*mock_ui(), SetFirstVisit(base::string16())); 373 374 // SetPermissionInfo() is called once initially, and then again every time 375 // OnSitePermissionChanged() is called. 376 // TODO(markusheintz): This is a temporary hack to fix issue: 377 // http://crbug.com/144203. 378#if defined(OS_MACOSX) 379 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(2); 380#else 381 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(1); 382#endif 383 384 EXPECT_CALL(*mock_ui(), SetSelectedTab( 385 WebsiteSettingsUI::TAB_ID_PERMISSIONS)); 386 EXPECT_EQ(0u, infobar_service()->infobar_count()); 387 website_settings()->OnSitePermissionChanged( 388 CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTING_ALLOW); 389 website_settings()->OnUIClosing(); 390 ASSERT_EQ(1u, infobar_service()->infobar_count()); 391 392 infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0)); 393} 394