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