1 // Copyright 2015 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/ssl/captive_portal_blocking_page.h"
9 #include "base/callback.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/run_loop.h"
14 #include "base/strings/stringprintf.h"
15 #include "chrome/browser/interstitials/security_interstitial_page_test_utils.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ssl/cert_report_helper.h"
18 #include "chrome/browser/ssl/certificate_reporting_test_utils.h"
19 #include "chrome/browser/ssl/ssl_cert_reporter.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "components/captive_portal/captive_portal_detector.h"
25 #include "content/public/browser/interstitial_page.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "net/cert/x509_certificate.h"
29 #include "testing/gtest/include/gtest/gtest.h"
32 using chrome_browser_interstitials::IsInterstitialDisplayingText
;
33 using chrome_browser_interstitials::SecurityInterstitialIDNTest
;
36 // Partial text in the captive portal interstitial's main paragraph when the
37 // login domain isn't displayed.
38 const char kGenericLoginURLText
[] = "its login page";
39 const char kBrokenSSL
[] = "https://broken.ssl";
40 const char kWiFiSSID
[] = "WiFiSSID";
59 class FakeConnectionInfoDelegate
: public CaptivePortalBlockingPage::Delegate
{
61 FakeConnectionInfoDelegate(bool is_wifi_connection
, std::string wifi_ssid
)
62 : is_wifi_connection_(is_wifi_connection
), wifi_ssid_(wifi_ssid
) {}
63 ~FakeConnectionInfoDelegate() override
{}
65 bool IsWifiConnection() const override
{ return is_wifi_connection_
; }
66 std::string
GetWiFiSSID() const override
{ return wifi_ssid_
; }
69 const bool is_wifi_connection_
;
70 const std::string wifi_ssid_
;
72 DISALLOW_COPY_AND_ASSIGN(FakeConnectionInfoDelegate
);
75 class CaptivePortalBlockingPageTest
76 : public CertificateReportingTestUtils::CertificateReportingTest
{
78 CaptivePortalBlockingPageTest() {}
80 void TestInterstitial(bool is_wifi_connection
,
81 const std::string
& wifi_ssid
,
82 const GURL
& login_url
,
83 ExpectWiFi expect_wifi
,
84 ExpectWiFiSSID expect_wifi_ssid
,
85 ExpectLoginURL expect_login_url
,
86 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
,
87 const std::string
& expected_login_hostname
);
89 void TestInterstitial(bool is_wifi_connection
,
90 const std::string
& wifi_ssid
,
91 const GURL
& login_url
,
92 ExpectWiFi expect_wifi
,
93 ExpectWiFiSSID expect_wifi_ssid
,
94 ExpectLoginURL expect_login_url
);
96 void TestInterstitial(bool is_wifi_connection
,
97 const std::string
& wifi_ssid
,
98 const GURL
& login_url
,
99 ExpectWiFi expect_wifi
,
100 ExpectWiFiSSID expect_wifi_ssid
,
101 ExpectLoginURL expect_login_url
,
102 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
);
104 void TestCertReporting(CertificateReportingTestUtils::OptIn opt_in
);
107 DISALLOW_COPY_AND_ASSIGN(CaptivePortalBlockingPageTest
);
110 void CaptivePortalBlockingPageTest::TestInterstitial(
111 bool is_wifi_connection
,
112 const std::string
& wifi_ssid
,
113 const GURL
& login_url
,
114 ExpectWiFi expect_wifi
,
115 ExpectWiFiSSID expect_wifi_ssid
,
116 ExpectLoginURL expect_login_url
,
117 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
,
118 const std::string
& expected_login_hostname
) {
119 content::WebContents
* contents
=
120 browser()->tab_strip_model()->GetActiveWebContents();
122 // Delegate is owned by the blocking page.
123 FakeConnectionInfoDelegate
* delegate
=
124 new FakeConnectionInfoDelegate(is_wifi_connection
, wifi_ssid
);
125 net::SSLInfo ssl_info
;
126 ssl_info
.cert
= new net::X509Certificate(
127 login_url
.host(), "CA", base::Time::Max(), base::Time::Max());
129 // Blocking page is owned by the interstitial.
130 CaptivePortalBlockingPage
* blocking_page
= new CaptivePortalBlockingPage(
131 contents
, GURL(kBrokenSSL
), login_url
, ssl_cert_reporter
.Pass(), ssl_info
,
132 base::Callback
<void(bool)>());
133 blocking_page
->SetDelegate(delegate
);
134 blocking_page
->Show();
136 WaitForInterstitialAttach(contents
);
138 WaitForRenderFrameReady(contents
->GetInterstitialPage()->GetMainFrame()));
139 EXPECT_EQ(expect_wifi
== EXPECT_WIFI_YES
,
140 IsInterstitialDisplayingText(contents
->GetInterstitialPage(),
142 if (!wifi_ssid
.empty()) {
143 EXPECT_EQ(expect_wifi_ssid
== EXPECT_WIFI_SSID_YES
,
144 IsInterstitialDisplayingText(contents
->GetInterstitialPage(),
147 EXPECT_EQ(expect_login_url
== EXPECT_LOGIN_URL_YES
,
148 IsInterstitialDisplayingText(contents
->GetInterstitialPage(),
149 expected_login_hostname
));
150 EXPECT_EQ(expect_login_url
== EXPECT_LOGIN_URL_NO
,
151 IsInterstitialDisplayingText(contents
->GetInterstitialPage(),
152 kGenericLoginURLText
));
155 void CaptivePortalBlockingPageTest::TestInterstitial(
156 bool is_wifi_connection
,
157 const std::string
& wifi_ssid
,
158 const GURL
& login_url
,
159 ExpectWiFi expect_wifi
,
160 ExpectWiFiSSID expect_wifi_ssid
,
161 ExpectLoginURL expect_login_url
) {
162 TestInterstitial(is_wifi_connection
, wifi_ssid
, login_url
, expect_wifi
,
163 expect_wifi_ssid
, expect_login_url
, nullptr,
167 void CaptivePortalBlockingPageTest::TestInterstitial(
168 bool is_wifi_connection
,
169 const std::string
& wifi_ssid
,
170 const GURL
& login_url
,
171 ExpectWiFi expect_wifi
,
172 ExpectWiFiSSID expect_wifi_ssid
,
173 ExpectLoginURL expect_login_url
,
174 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
) {
175 TestInterstitial(is_wifi_connection
, wifi_ssid
, login_url
, expect_wifi
,
176 expect_wifi_ssid
, expect_login_url
, ssl_cert_reporter
.Pass(),
180 void CaptivePortalBlockingPageTest::TestCertReporting(
181 CertificateReportingTestUtils::OptIn opt_in
) {
182 ASSERT_NO_FATAL_FAILURE(SetUpMockReporter());
184 CertificateReportingTestUtils::SetCertReportingOptIn(browser(), opt_in
);
185 base::RunLoop run_loop
;
186 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
=
187 CertificateReportingTestUtils::SetUpMockSSLCertReporter(
189 opt_in
== CertificateReportingTestUtils::EXTENDED_REPORTING_OPT_IN
190 ? CertificateReportingTestUtils::CERT_REPORT_EXPECTED
191 : CertificateReportingTestUtils::CERT_REPORT_NOT_EXPECTED
);
193 const GURL
kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL
);
194 TestInterstitial(true, std::string(), kLandingUrl
, EXPECT_WIFI_YES
,
195 EXPECT_WIFI_SSID_NO
, EXPECT_LOGIN_URL_NO
,
196 ssl_cert_reporter
.Pass());
198 EXPECT_EQ(std::string(), GetLatestHostnameReported());
200 content::WebContents
* tab
=
201 browser()->tab_strip_model()->GetActiveWebContents();
202 tab
->GetInterstitialPage()->DontProceed();
204 if (opt_in
== CertificateReportingTestUtils::EXTENDED_REPORTING_OPT_IN
) {
205 // Check that the mock reporter received a request to send a report.
207 EXPECT_EQ(GURL(kBrokenSSL
).host(), GetLatestHostnameReported());
209 EXPECT_EQ(std::string(), GetLatestHostnameReported());
213 // If the connection is not a Wi-Fi connection, the wired network version of the
214 // captive portal interstitial should be displayed.
215 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
216 WiredNetwork_LoginURL
) {
217 TestInterstitial(false, std::string(),
218 GURL("http://captive.portal/landing_url"), EXPECT_WIFI_NO
,
219 EXPECT_WIFI_SSID_NO
, EXPECT_LOGIN_URL_YES
);
222 // Same as above, but SSID is available, so the connection should be assumed to
224 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
225 WiredNetwork_LoginURL_With_SSID
) {
226 TestInterstitial(false, kWiFiSSID
, GURL("http://captive.portal/landing_url"),
227 EXPECT_WIFI_YES
, EXPECT_WIFI_SSID_YES
, EXPECT_LOGIN_URL_YES
);
230 // Same as above, expect the login URL is the same as the captive portal ping
231 // url (i.e. the portal intercepts requests without using HTTP redirects), in
232 // which case the login URL shouldn't be displayed.
233 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
234 WiredNetwork_NoLoginURL
) {
235 const GURL
kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL
);
236 TestInterstitial(false, std::string(), kLandingUrl
, EXPECT_WIFI_NO
,
237 EXPECT_WIFI_SSID_NO
, EXPECT_LOGIN_URL_NO
);
240 // Same as above, but SSID is available, so the connection should be assumed to
242 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
243 WiredNetwork_NoLoginURL_With_SSID
) {
244 const GURL
kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL
);
245 TestInterstitial(false, kWiFiSSID
, kLandingUrl
, EXPECT_WIFI_YES
,
246 EXPECT_WIFI_SSID_YES
, EXPECT_LOGIN_URL_NO
);
249 // If the connection is a Wi-Fi connection, the Wi-Fi version of the captive
250 // portal interstitial should be displayed.
251 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
252 WiFi_SSID_LoginURL
) {
253 TestInterstitial(true, kWiFiSSID
, GURL("http://captive.portal/landing_url"),
254 EXPECT_WIFI_YES
, EXPECT_WIFI_SSID_YES
, EXPECT_LOGIN_URL_YES
);
257 // Same as above, with login URL but no SSID.
258 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
259 WiFi_NoSSID_LoginURL
) {
260 TestInterstitial(true, std::string(),
261 GURL("http://captive.portal/landing_url"), EXPECT_WIFI_YES
,
262 EXPECT_WIFI_SSID_NO
, EXPECT_LOGIN_URL_YES
);
265 // Same as above, with SSID but no login URL.
266 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
267 WiFi_SSID_NoLoginURL
) {
268 const GURL
kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL
);
269 TestInterstitial(true, kWiFiSSID
, kLandingUrl
,
270 EXPECT_WIFI_YES
, EXPECT_WIFI_SSID_YES
, EXPECT_LOGIN_URL_NO
);
273 // Same as above, with no SSID and no login URL.
274 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
,
275 WiFi_NoSSID_NoLoginURL
) {
276 const GURL
kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL
);
277 TestInterstitial(true, std::string(), kLandingUrl
, EXPECT_WIFI_YES
,
278 EXPECT_WIFI_SSID_NO
, EXPECT_LOGIN_URL_NO
);
281 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
, CertReportingOptIn
) {
282 // This test should only run if the Finch config is such that reports
283 // will be sent when opted in. This tests that a report *is* sent when
284 // the user opts in under such a Finch config, and the below test
285 // tests that a report *is not* sent when the user doesn't opt in
286 // (under any Finch config).
287 if (CertificateReportingTestUtils::GetReportExpectedFromFinch() ==
288 CertificateReportingTestUtils::CERT_REPORT_EXPECTED
) {
289 TestCertReporting(CertificateReportingTestUtils::EXTENDED_REPORTING_OPT_IN
);
293 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest
, CertReportingOptOut
) {
295 CertificateReportingTestUtils::EXTENDED_REPORTING_DO_NOT_OPT_IN
);
298 class CaptivePortalBlockingPageIDNTest
: public SecurityInterstitialIDNTest
{
300 // SecurityInterstitialIDNTest implementation
301 SecurityInterstitialPage
* CreateInterstitial(
302 content::WebContents
* contents
,
303 const GURL
& request_url
) const override
{
304 // Delegate is owned by the blocking page.
305 FakeConnectionInfoDelegate
* delegate
=
306 new FakeConnectionInfoDelegate(false, std::string());
307 net::SSLInfo empty_ssl_info
;
308 // Blocking page is owned by the interstitial.
309 CaptivePortalBlockingPage
* blocking_page
= new CaptivePortalBlockingPage(
310 contents
, GURL(kBrokenSSL
), request_url
, nullptr, empty_ssl_info
,
311 base::Callback
<void(bool)>());
312 blocking_page
->SetDelegate(delegate
);
313 return blocking_page
;
317 // Test that an IDN login domain is decoded properly.
318 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageIDNTest
,
319 ShowLoginIDNIfPortalRedirectsDetectionURL
) {
320 EXPECT_TRUE(VerifyIDNDecoded());