Home | History | Annotate | Download | only in website_settings
      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