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.
5 #include "chrome/browser/ui/website_settings/website_settings.h"
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/infobars/infobar_service.h"
12 #include "chrome/browser/ui/website_settings/website_settings_ui.h"
13 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "components/content_settings/core/browser/host_content_settings_map.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"
28 using content::SSLStatus
;
30 using testing::AnyNumber
;
31 using testing::Return
;
32 using testing::SetArgPointee
;
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.
38 int CR_TLS_RSA_WITH_AES_256_CBC_SHA256
= 0x3D;
40 int SetSSLVersion(int connection_status
, int version
) {
41 // Clear SSL version bits (Bits 20, 21 and 22).
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
;
48 int 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
;
54 class MockCertStore
: public content::CertStore
{
56 virtual ~MockCertStore() {}
57 MOCK_METHOD2(StoreCert
, int(net::X509Certificate
*, int));
58 MOCK_METHOD2(RetrieveCert
, bool(int, scoped_refptr
<net::X509Certificate
>*));
61 class MockWebsiteSettingsUI
: public WebsiteSettingsUI
{
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(SetSelectedTab
, void(TabId tab_id
));
71 class WebsiteSettingsTest
: public ChromeRenderViewHostTestHarness
{
73 WebsiteSettingsTest() : cert_id_(0), url_("http://www.example.com") {}
75 ~WebsiteSettingsTest() override
{}
77 void SetUp() override
{
78 ChromeRenderViewHostTestHarness::SetUp();
79 // Setup stub SSLStatus.
80 ssl_
.security_style
= content::SECURITY_STYLE_UNAUTHENTICATED
;
82 // Create the certificate.
84 base::Time start_date
= base::Time::Now();
85 base::Time expiration_date
= base::Time::FromInternalValue(
86 start_date
.ToInternalValue() + base::Time::kMicrosecondsPerWeek
);
87 cert_
= new net::X509Certificate("subject",
92 TabSpecificContentSettings::CreateForWebContents(web_contents());
93 InfoBarService::CreateForWebContents(web_contents());
95 // Setup the mock cert store.
96 EXPECT_CALL(cert_store_
, RetrieveCert(cert_id_
, _
) )
98 .WillRepeatedly(DoAll(SetArgPointee
<1>(cert_
), Return(true)));
101 mock_ui_
.reset(new MockWebsiteSettingsUI());
104 void TearDown() override
{
105 ASSERT_TRUE(website_settings_
.get())
106 << "No WebsiteSettings instance created.";
107 RenderViewHostTestHarness::TearDown();
108 website_settings_
.reset();
111 void SetDefaultUIExpectations(MockWebsiteSettingsUI
* mock_ui
) {
112 // During creation |WebsiteSettings| makes the following calls to the ui.
113 EXPECT_CALL(*mock_ui
, SetPermissionInfo(_
));
114 EXPECT_CALL(*mock_ui
, SetIdentityInfo(_
));
115 EXPECT_CALL(*mock_ui
, SetCookieInfo(_
));
118 void SetURL(std::string url
) { url_
= GURL(url
); }
120 const GURL
& url() const { return url_
; }
121 MockCertStore
* cert_store() { return &cert_store_
; }
122 int cert_id() { return cert_id_
; }
123 MockWebsiteSettingsUI
* mock_ui() { return mock_ui_
.get(); }
124 const SSLStatus
& ssl() { return ssl_
; }
125 TabSpecificContentSettings
* tab_specific_content_settings() {
126 return TabSpecificContentSettings::FromWebContents(web_contents());
128 InfoBarService
* infobar_service() {
129 return InfoBarService::FromWebContents(web_contents());
132 WebsiteSettings
* website_settings() {
133 if (!website_settings_
.get()) {
134 website_settings_
.reset(new WebsiteSettings(
135 mock_ui(), profile(), tab_specific_content_settings(),
136 web_contents(), url(), ssl(), cert_store()));
138 return website_settings_
.get();
144 scoped_ptr
<WebsiteSettings
> website_settings_
;
145 scoped_ptr
<MockWebsiteSettingsUI
> mock_ui_
;
147 scoped_refptr
<net::X509Certificate
> cert_
;
148 MockCertStore cert_store_
;
154 TEST_F(WebsiteSettingsTest
, OnPermissionsChanged
) {
155 // Setup site permissions.
156 HostContentSettingsMap
* content_settings
=
157 profile()->GetHostContentSettingsMap();
158 ContentSetting setting
= content_settings
->GetContentSetting(
159 url(), url(), CONTENT_SETTINGS_TYPE_POPUPS
, std::string());
160 EXPECT_EQ(setting
, CONTENT_SETTING_BLOCK
);
161 setting
= content_settings
->GetContentSetting(
162 url(), url(), CONTENT_SETTINGS_TYPE_PLUGINS
, std::string());
163 EXPECT_EQ(setting
, CONTENT_SETTING_ALLOW
);
164 setting
= content_settings
->GetContentSetting(
165 url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION
, std::string());
166 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
167 setting
= content_settings
->GetContentSetting(
168 url(), url(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS
, std::string());
169 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
170 setting
= content_settings
->GetContentSetting(
171 url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
, std::string());
172 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
173 setting
= content_settings
->GetContentSetting(
174 url(), url(), CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
, std::string());
175 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
177 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_
));
178 EXPECT_CALL(*mock_ui(), SetCookieInfo(_
));
180 // SetPermissionInfo() is called once initially, and then again every time
181 // OnSitePermissionChanged() is called.
182 // TODO(markusheintz): This is a temporary hack to fix issue: http://crbug.com/144203.
183 #if defined(OS_MACOSX)
184 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
)).Times(7);
186 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
)).Times(1);
188 EXPECT_CALL(*mock_ui(), SetSelectedTab(
189 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
191 // Execute code under tests.
192 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_POPUPS
,
193 CONTENT_SETTING_ALLOW
);
194 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_PLUGINS
,
195 CONTENT_SETTING_BLOCK
);
196 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_GEOLOCATION
,
197 CONTENT_SETTING_ALLOW
);
198 website_settings()->OnSitePermissionChanged(
199 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
, CONTENT_SETTING_ALLOW
);
200 website_settings()->OnSitePermissionChanged(
201 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
, CONTENT_SETTING_ALLOW
);
202 website_settings()->OnSitePermissionChanged(
203 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
, CONTENT_SETTING_ALLOW
);
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
);
226 TEST_F(WebsiteSettingsTest
, OnPermissionsChanged_Fullscreen
) {
227 // Setup site permissions.
228 HostContentSettingsMap
* content_settings
=
229 profile()->GetHostContentSettingsMap();
230 ContentSetting setting
= content_settings
->GetContentSetting(
231 url(), url(), CONTENT_SETTINGS_TYPE_FULLSCREEN
, std::string());
232 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
234 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_
));
235 EXPECT_CALL(*mock_ui(), SetCookieInfo(_
));
236 EXPECT_CALL(*mock_ui(), SetSelectedTab(
237 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
239 // SetPermissionInfo() is called once initially, and then again every time
240 // OnSitePermissionChanged() is called.
241 // TODO(markusheintz): This is a temporary hack to fix issue:
242 // http://crbug.com/144203.
243 #if defined(OS_MACOSX)
244 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
)).Times(3);
246 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
)).Times(1);
249 // Execute code under tests.
250 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_FULLSCREEN
,
251 CONTENT_SETTING_ALLOW
);
253 // Verify that the site permissions were changed correctly.
254 setting
= content_settings
->GetContentSetting(
255 url(), url(), CONTENT_SETTINGS_TYPE_FULLSCREEN
, std::string());
256 EXPECT_EQ(setting
, CONTENT_SETTING_ALLOW
);
258 // ... and that the primary pattern must match the secondary one.
259 setting
= content_settings
->GetContentSetting(
260 url(), GURL("https://test.com"),
261 CONTENT_SETTINGS_TYPE_FULLSCREEN
, std::string());
262 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
265 // Resetting the setting should move the permission back to ASK.
266 website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_FULLSCREEN
,
267 CONTENT_SETTING_ASK
);
269 setting
= content_settings
->GetContentSetting(
270 url(), url(), CONTENT_SETTINGS_TYPE_FULLSCREEN
, std::string());
271 EXPECT_EQ(setting
, CONTENT_SETTING_ASK
);
274 TEST_F(WebsiteSettingsTest
, OnSiteDataAccessed
) {
275 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
));
276 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_
));
277 EXPECT_CALL(*mock_ui(), SetCookieInfo(_
)).Times(2);
278 EXPECT_CALL(*mock_ui(), SetSelectedTab(
279 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
281 website_settings()->OnSiteDataAccessed();
284 TEST_F(WebsiteSettingsTest
, HTTPConnection
) {
285 SetDefaultUIExpectations(mock_ui());
286 EXPECT_CALL(*mock_ui(), SetSelectedTab(
287 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
288 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED
,
289 website_settings()->site_connection_status());
290 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_NO_CERT
,
291 website_settings()->site_identity_status());
292 EXPECT_EQ(base::string16(), website_settings()->organization_name());
295 TEST_F(WebsiteSettingsTest
, HTTPSConnection
) {
296 ssl_
.security_style
= content::SECURITY_STYLE_AUTHENTICATED
;
297 ssl_
.cert_id
= cert_id();
298 ssl_
.cert_status
= 0;
299 ssl_
.security_bits
= 81; // No error if > 80.
301 status
= SetSSLVersion(status
, net::SSL_CONNECTION_VERSION_TLS1
);
302 status
= SetSSLCipherSuite(status
, CR_TLS_RSA_WITH_AES_256_CBC_SHA256
);
303 ssl_
.connection_status
= status
;
305 SetDefaultUIExpectations(mock_ui());
306 EXPECT_CALL(*mock_ui(), SetSelectedTab(
307 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
309 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED
,
310 website_settings()->site_connection_status());
311 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT
,
312 website_settings()->site_identity_status());
313 EXPECT_EQ(base::string16(), website_settings()->organization_name());
316 TEST_F(WebsiteSettingsTest
, HTTPSMixedContent
) {
317 ssl_
.security_style
= content::SECURITY_STYLE_AUTHENTICATED
;
318 ssl_
.cert_id
= cert_id();
319 ssl_
.cert_status
= 0;
320 ssl_
.security_bits
= 81; // No error if > 80.
321 ssl_
.content_status
= SSLStatus::DISPLAYED_INSECURE_CONTENT
;
323 status
= SetSSLVersion(status
, net::SSL_CONNECTION_VERSION_TLS1
);
324 status
= SetSSLCipherSuite(status
, CR_TLS_RSA_WITH_AES_256_CBC_SHA256
);
325 ssl_
.connection_status
= status
;
327 SetDefaultUIExpectations(mock_ui());
328 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION
));
330 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_MIXED_CONTENT
,
331 website_settings()->site_connection_status());
332 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT
,
333 website_settings()->site_identity_status());
334 EXPECT_EQ(base::string16(), website_settings()->organization_name());
337 TEST_F(WebsiteSettingsTest
, HTTPSEVCert
) {
338 scoped_refptr
<net::X509Certificate
> ev_cert
=
339 net::X509Certificate::CreateFromBytes(
340 reinterpret_cast<const char*>(google_der
),
343 EXPECT_CALL(*cert_store(), RetrieveCert(ev_cert_id
, _
)).WillRepeatedly(
344 DoAll(SetArgPointee
<1>(ev_cert
), Return(true)));
346 ssl_
.security_style
= content::SECURITY_STYLE_AUTHENTICATED
;
347 ssl_
.cert_id
= ev_cert_id
;
348 ssl_
.cert_status
= net::CERT_STATUS_IS_EV
;
349 ssl_
.security_bits
= 81; // No error if > 80.
350 ssl_
.content_status
= SSLStatus::DISPLAYED_INSECURE_CONTENT
;
352 status
= SetSSLVersion(status
, net::SSL_CONNECTION_VERSION_TLS1
);
353 status
= SetSSLCipherSuite(status
, CR_TLS_RSA_WITH_AES_256_CBC_SHA256
);
354 ssl_
.connection_status
= status
;
356 SetDefaultUIExpectations(mock_ui());
357 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION
));
359 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_MIXED_CONTENT
,
360 website_settings()->site_connection_status());
361 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT
,
362 website_settings()->site_identity_status());
363 EXPECT_EQ(base::UTF8ToUTF16("Google Inc"),
364 website_settings()->organization_name());
367 TEST_F(WebsiteSettingsTest
, HTTPSRevocationError
) {
368 ssl_
.security_style
= content::SECURITY_STYLE_AUTHENTICATED
;
369 ssl_
.cert_id
= cert_id();
370 ssl_
.cert_status
= net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION
;
371 ssl_
.security_bits
= 81; // No error if > 80.
373 status
= SetSSLVersion(status
, net::SSL_CONNECTION_VERSION_TLS1
);
374 status
= SetSSLCipherSuite(status
, CR_TLS_RSA_WITH_AES_256_CBC_SHA256
);
375 ssl_
.connection_status
= status
;
377 SetDefaultUIExpectations(mock_ui());
378 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION
));
380 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED
,
381 website_settings()->site_connection_status());
382 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN
,
383 website_settings()->site_identity_status());
384 EXPECT_EQ(base::string16(), website_settings()->organization_name());
387 TEST_F(WebsiteSettingsTest
, HTTPSConnectionError
) {
388 ssl_
.security_style
= content::SECURITY_STYLE_AUTHENTICATED
;
389 ssl_
.cert_id
= cert_id();
390 ssl_
.cert_status
= 0;
391 ssl_
.security_bits
= -1;
393 status
= SetSSLVersion(status
, net::SSL_CONNECTION_VERSION_TLS1
);
394 status
= SetSSLCipherSuite(status
, CR_TLS_RSA_WITH_AES_256_CBC_SHA256
);
395 ssl_
.connection_status
= status
;
397 SetDefaultUIExpectations(mock_ui());
398 EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION
));
400 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR
,
401 website_settings()->site_connection_status());
402 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_CERT
,
403 website_settings()->site_identity_status());
404 EXPECT_EQ(base::string16(), website_settings()->organization_name());
407 #if !defined(OS_ANDROID)
408 TEST_F(WebsiteSettingsTest
, NoInfoBar
) {
409 SetDefaultUIExpectations(mock_ui());
410 EXPECT_CALL(*mock_ui(), SetSelectedTab(
411 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
412 EXPECT_EQ(0u, infobar_service()->infobar_count());
413 website_settings()->OnUIClosing();
414 EXPECT_EQ(0u, infobar_service()->infobar_count());
417 TEST_F(WebsiteSettingsTest
, ShowInfoBar
) {
418 EXPECT_CALL(*mock_ui(), SetIdentityInfo(_
));
419 EXPECT_CALL(*mock_ui(), SetCookieInfo(_
));
421 // SetPermissionInfo() is called once initially, and then again every time
422 // OnSitePermissionChanged() is called.
423 // TODO(markusheintz): This is a temporary hack to fix issue:
424 // http://crbug.com/144203.
425 #if defined(OS_MACOSX)
426 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
)).Times(2);
428 EXPECT_CALL(*mock_ui(), SetPermissionInfo(_
)).Times(1);
431 EXPECT_CALL(*mock_ui(), SetSelectedTab(
432 WebsiteSettingsUI::TAB_ID_PERMISSIONS
));
433 EXPECT_EQ(0u, infobar_service()->infobar_count());
434 website_settings()->OnSitePermissionChanged(
435 CONTENT_SETTINGS_TYPE_GEOLOCATION
, CONTENT_SETTING_ALLOW
);
436 website_settings()->OnUIClosing();
437 ASSERT_EQ(1u, infobar_service()->infobar_count());
439 infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0));
443 TEST_F(WebsiteSettingsTest
, AboutBlankPage
) {
444 SetURL("about:blank");
445 SetDefaultUIExpectations(mock_ui());
446 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_INTERNAL_PAGE
,
447 website_settings()->site_connection_status());
448 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_INTERNAL_PAGE
,
449 website_settings()->site_identity_status());
450 EXPECT_EQ(base::string16(), website_settings()->organization_name());
453 TEST_F(WebsiteSettingsTest
, InternalPage
) {
454 SetURL("chrome://bookmarks");
455 SetDefaultUIExpectations(mock_ui());
456 EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_INTERNAL_PAGE
,
457 website_settings()->site_connection_status());
458 EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_INTERNAL_PAGE
,
459 website_settings()->site_identity_status());
460 EXPECT_EQ(base::string16(), website_settings()->organization_name());