blob: 4e67c9f64bd483db44e8bd22bfde378e79a00fc7 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/website_settings/website_settings.h"
#include "base/at_exit.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/ui/website_settings/website_settings_ui.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/infobars/core/infobar.h"
#include "content/public/browser/cert_store.h"
#include "content/public/common/ssl_status.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/test/test_certificate_data.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::SSLStatus;
using testing::_;
using testing::AnyNumber;
using testing::Return;
using testing::SetArgPointee;
namespace {
// SSL cipher suite like specified in RFC5246 Appendix A.5. "The Cipher Suite".
// Without the CR_ prefix, this clashes with the OS X 10.8 headers.
int CR_TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3D;
int SetSSLVersion(int connection_status, int version) {
// Clear SSL version bits (Bits 20, 21 and 22).
connection_status &=
~(net::SSL_CONNECTION_VERSION_MASK << net::SSL_CONNECTION_VERSION_SHIFT);
int bitmask = version << net::SSL_CONNECTION_VERSION_SHIFT;
return bitmask | connection_status;
}
int SetSSLCipherSuite(int connection_status, int cipher_suite) {
// Clear cipher suite bits (the 16 lowest bits).
connection_status &= ~net::SSL_CONNECTION_CIPHERSUITE_MASK;
return cipher_suite | connection_status;
}
class MockCertStore : public content::CertStore {
public:
virtual ~MockCertStore() {}
MOCK_METHOD2(StoreCert, int(net::X509Certificate*, int));
MOCK_METHOD2(RetrieveCert, bool(int, scoped_refptr<net::X509Certificate>*));
};
class MockWebsiteSettingsUI : public WebsiteSettingsUI {
public:
virtual ~MockWebsiteSettingsUI() {}
MOCK_METHOD1(SetCookieInfo, void(const CookieInfoList& cookie_info_list));
MOCK_METHOD1(SetPermissionInfo,
void(const PermissionInfoList& permission_info_list));
MOCK_METHOD1(SetIdentityInfo, void(const IdentityInfo& identity_info));
MOCK_METHOD1(SetFirstVisit, void(const base::string16& first_visit));
MOCK_METHOD1(SetSelectedTab, void(TabId tab_id));
};
class WebsiteSettingsTest : public ChromeRenderViewHostTestHarness {
public:
WebsiteSettingsTest() : cert_id_(0), url_("http://www.example.com") {}
~WebsiteSettingsTest() override {}
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
// Setup stub SSLStatus.
ssl_.security_style = content::SECURITY_STYLE_UNAUTHENTICATED;
// Create the certificate.
cert_id_ = 1;
base::Time start_date = base::Time::Now();
base::Time expiration_date = base::Time::FromInternalValue(
start_date.ToInternalValue() + base::Time::kMicrosecondsPerWeek);
cert_ = new net::X509Certificate("subject",
"issuer",
start_date,
expiration_date);
TabSpecificContentSettings::CreateForWebContents(web_contents());
InfoBarService::CreateForWebContents(web_contents());
// Setup the mock cert store.
EXPECT_CALL(cert_store_, RetrieveCert(cert_id_, _) )
.Times(AnyNumber())
.WillRepeatedly(DoAll(SetArgPointee<1>(cert_), Return(true)));
// Setup mock ui.
mock_ui_.reset(new MockWebsiteSettingsUI());
}
void TearDown() override {
ASSERT_TRUE(website_settings_.get())
<< "No WebsiteSettings instance created.";
RenderViewHostTestHarness::TearDown();
website_settings_.reset();
}
void SetDefaultUIExpectations(MockWebsiteSettingsUI* mock_ui) {
// During creation |WebsiteSettings| makes the following calls to the ui.
EXPECT_CALL(*mock_ui, SetPermissionInfo(_));
EXPECT_CALL(*mock_ui, SetIdentityInfo(_));
EXPECT_CALL(*mock_ui, SetCookieInfo(_));
EXPECT_CALL(*mock_ui, SetFirstVisit(base::string16()));
}
void SetURL(std::string url) { url_ = GURL(url); }
const GURL& url() const { return url_; }
MockCertStore* cert_store() { return &cert_store_; }
int cert_id() { return cert_id_; }
MockWebsiteSettingsUI* mock_ui() { return mock_ui_.get(); }
const SSLStatus& ssl() { return ssl_; }
TabSpecificContentSettings* tab_specific_content_settings() {
return TabSpecificContentSettings::FromWebContents(web_contents());
}
InfoBarService* infobar_service() {
return InfoBarService::FromWebContents(web_contents());
}
WebsiteSettings* website_settings() {
if (!website_settings_.get()) {
website_settings_.reset(new WebsiteSettings(
mock_ui(), profile(), tab_specific_content_settings(),
infobar_service(), url(), ssl(), cert_store()));
}
return website_settings_.get();
}
SSLStatus ssl_;
private:
scoped_ptr<WebsiteSettings> website_settings_;
scoped_ptr<MockWebsiteSettingsUI> mock_ui_;
int cert_id_;
scoped_refptr<net::X509Certificate> cert_;
MockCertStore cert_store_;
GURL url_;
};
} // namespace
TEST_F(WebsiteSettingsTest, OnPermissionsChanged) {
// Setup site permissions.
HostContentSettingsMap* content_settings =
profile()->GetHostContentSettingsMap();
ContentSetting setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_POPUPS, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ASK);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ASK);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ASK);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ASK);
EXPECT_CALL(*mock_ui(), SetIdentityInfo(_));
EXPECT_CALL(*mock_ui(), SetCookieInfo(_));
EXPECT_CALL(*mock_ui(), SetFirstVisit(base::string16()));
// SetPermissionInfo() is called once initially, and then again every time
// OnSitePermissionChanged() is called.
// TODO(markusheintz): This is a temporary hack to fix issue: http://crbug.com/144203.
#if defined(OS_MACOSX)
EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(6);
#else
EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(1);
#endif
EXPECT_CALL(*mock_ui(), SetSelectedTab(
WebsiteSettingsUI::TAB_ID_PERMISSIONS));
// Execute code under tests.
website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_POPUPS,
CONTENT_SETTING_ALLOW);
website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_PLUGINS,
CONTENT_SETTING_BLOCK);
website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_GEOLOCATION,
CONTENT_SETTING_ALLOW);
website_settings()->OnSitePermissionChanged(
CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW);
website_settings()->OnSitePermissionChanged(
CONTENT_SETTINGS_TYPE_MEDIASTREAM, CONTENT_SETTING_ALLOW);
// Verify that the site permissions were changed correctly.
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_POPUPS, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
setting = content_settings->GetContentSetting(
url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string());
EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
}
TEST_F(WebsiteSettingsTest, OnSiteDataAccessed) {
EXPECT_CALL(*mock_ui(), SetPermissionInfo(_));
EXPECT_CALL(*mock_ui(), SetIdentityInfo(_));
EXPECT_CALL(*mock_ui(), SetFirstVisit(base::string16()));
EXPECT_CALL(*mock_ui(), SetCookieInfo(_)).Times(2);
EXPECT_CALL(*mock_ui(), SetSelectedTab(
WebsiteSettingsUI::TAB_ID_PERMISSIONS));
website_settings()->OnSiteDataAccessed();
}
TEST_F(WebsiteSettingsTest, HTTPConnection) {
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(
WebsiteSettingsUI::TAB_ID_PERMISSIONS));
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_NO_CERT,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, HTTPSConnection) {
ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED;
ssl_.cert_id = cert_id();
ssl_.cert_status = 0;
ssl_.security_bits = 81; // No error if > 80.
int status = 0;
status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
ssl_.connection_status = status;
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(
WebsiteSettingsUI::TAB_ID_PERMISSIONS));
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, HTTPSMixedContent) {
ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED;
ssl_.cert_id = cert_id();
ssl_.cert_status = 0;
ssl_.security_bits = 81; // No error if > 80.
ssl_.content_status = SSLStatus::DISPLAYED_INSECURE_CONTENT;
int status = 0;
status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
ssl_.connection_status = status;
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION));
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_MIXED_CONTENT,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, HTTPSEVCert) {
scoped_refptr<net::X509Certificate> ev_cert =
net::X509Certificate::CreateFromBytes(
reinterpret_cast<const char*>(google_der),
sizeof(google_der));
int ev_cert_id = 1;
EXPECT_CALL(*cert_store(), RetrieveCert(ev_cert_id, _)).WillRepeatedly(
DoAll(SetArgPointee<1>(ev_cert), Return(true)));
ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED;
ssl_.cert_id = ev_cert_id;
ssl_.cert_status = net::CERT_STATUS_IS_EV;
ssl_.security_bits = 81; // No error if > 80.
ssl_.content_status = SSLStatus::DISPLAYED_INSECURE_CONTENT;
int status = 0;
status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
ssl_.connection_status = status;
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION));
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_MIXED_CONTENT,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT,
website_settings()->site_identity_status());
EXPECT_EQ(base::UTF8ToUTF16("Google Inc"),
website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, HTTPSRevocationError) {
ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED;
ssl_.cert_id = cert_id();
ssl_.cert_status = net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
ssl_.security_bits = 81; // No error if > 80.
int status = 0;
status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
ssl_.connection_status = status;
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION));
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, HTTPSConnectionError) {
ssl_.security_style = content::SECURITY_STYLE_AUTHENTICATED;
ssl_.cert_id = cert_id();
ssl_.cert_status = 0;
ssl_.security_bits = 1;
int status = 0;
status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
ssl_.connection_status = status;
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION));
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, NoInfoBar) {
SetDefaultUIExpectations(mock_ui());
EXPECT_CALL(*mock_ui(), SetSelectedTab(
WebsiteSettingsUI::TAB_ID_PERMISSIONS));
EXPECT_EQ(0u, infobar_service()->infobar_count());
website_settings()->OnUIClosing();
EXPECT_EQ(0u, infobar_service()->infobar_count());
}
TEST_F(WebsiteSettingsTest, ShowInfoBar) {
EXPECT_CALL(*mock_ui(), SetIdentityInfo(_));
EXPECT_CALL(*mock_ui(), SetCookieInfo(_));
EXPECT_CALL(*mock_ui(), SetFirstVisit(base::string16()));
// SetPermissionInfo() is called once initially, and then again every time
// OnSitePermissionChanged() is called.
// TODO(markusheintz): This is a temporary hack to fix issue:
// http://crbug.com/144203.
#if defined(OS_MACOSX)
EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(2);
#else
EXPECT_CALL(*mock_ui(), SetPermissionInfo(_)).Times(1);
#endif
EXPECT_CALL(*mock_ui(), SetSelectedTab(
WebsiteSettingsUI::TAB_ID_PERMISSIONS));
EXPECT_EQ(0u, infobar_service()->infobar_count());
website_settings()->OnSitePermissionChanged(
CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTING_ALLOW);
website_settings()->OnUIClosing();
ASSERT_EQ(1u, infobar_service()->infobar_count());
infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0));
}
TEST_F(WebsiteSettingsTest, AboutBlankPage) {
SetURL("about:blank");
SetDefaultUIExpectations(mock_ui());
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_INTERNAL_PAGE,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_INTERNAL_PAGE,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}
TEST_F(WebsiteSettingsTest, InternalPage) {
SetURL("chrome://bookmarks");
SetDefaultUIExpectations(mock_ui());
EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_INTERNAL_PAGE,
website_settings()->site_connection_status());
EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_INTERNAL_PAGE,
website_settings()->site_identity_status());
EXPECT_EQ(base::string16(), website_settings()->organization_name());
}