OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ssl/captive_portal_blocking_page.h" | 5 #include "chrome/browser/ssl/captive_portal_blocking_page.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "base/prefs/pref_service.h" | 12 #include "base/prefs/pref_service.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
15 #include "chrome/browser/ui/browser.h" | 15 #include "chrome/browser/ui/browser.h" |
16 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 16 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
17 #include "chrome/common/pref_names.h" | 17 #include "chrome/common/pref_names.h" |
18 #include "chrome/test/base/in_process_browser_test.h" | 18 #include "chrome/test/base/in_process_browser_test.h" |
19 #include "components/captive_portal/captive_portal_detector.h" | 19 #include "components/captive_portal/captive_portal_detector.h" |
20 #include "content/public/browser/interstitial_page.h" | 20 #include "content/public/browser/interstitial_page.h" |
21 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
22 #include "content/public/test/browser_test_utils.h" | 22 #include "content/public/test/browser_test_utils.h" |
23 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
24 #include "url/gurl.h" | 24 #include "url/gurl.h" |
25 | 25 |
| 26 namespace { |
26 // Partial text in the captive portal interstitial's main paragraph when the | 27 // Partial text in the captive portal interstitial's main paragraph when the |
27 // login domain isn't displayed. | 28 // login domain isn't displayed. |
28 const char kGenericLoginURLText[] = "its login page"; | 29 const char kGenericLoginURLText[] = "its login page"; |
29 const char kBrokenSSL[] = "https://broken.ssl"; | 30 const char kBrokenSSL[] = "https://broken.ssl"; |
| 31 const char kWiFiSSID[] = "WiFiSSID"; |
30 | 32 |
31 // Returns true if the interstitial contains |text| in its body. | 33 // Returns true if the interstitial contains |text| in its body. |
32 bool IsInterstitialDisplayingText(content::InterstitialPage* interstitial, | 34 bool IsInterstitialDisplayingText(content::InterstitialPage* interstitial, |
33 const std::string& text) { | 35 const std::string& text) { |
34 // It's valid for |text| to contain "\'", but simply look for "'" instead | 36 // It's valid for |text| to contain "\'", but simply look for "'" instead |
35 // since this function is used for searching host names and a predefined | 37 // since this function is used for searching host names and a predefined |
36 // string. | 38 // string. |
37 DCHECK(text.find("\'") == std::string::npos); | 39 DCHECK(text.find("\'") == std::string::npos); |
38 std::string command = base::StringPrintf( | 40 std::string command = base::StringPrintf( |
39 "var hasText = document.body.textContent.indexOf('%s') >= 0;" | 41 "var hasText = document.body.textContent.indexOf('%s') >= 0;" |
40 "window.domAutomationController.send(hasText);", | 42 "window.domAutomationController.send(hasText);", |
41 text.c_str()); | 43 text.c_str()); |
42 bool result = false; | 44 bool result = false; |
43 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( | 45 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
44 interstitial->GetMainFrame(), command, &result)); | 46 interstitial->GetMainFrame(), command, &result)); |
45 return result; | 47 return result; |
46 } | 48 } |
47 | 49 |
| 50 enum ExpectWiFi { |
| 51 EXPECT_WIFI_NO, |
| 52 EXPECT_WIFI_YES |
| 53 }; |
| 54 |
| 55 enum ExpectWiFiSSID { |
| 56 EXPECT_WIFI_SSID_NO, |
| 57 EXPECT_WIFI_SSID_YES |
| 58 }; |
| 59 |
| 60 enum ExpectLoginURL { |
| 61 EXPECT_LOGIN_URL_NO, |
| 62 EXPECT_LOGIN_URL_YES |
| 63 }; |
| 64 |
| 65 } // namespace |
| 66 |
48 class CaptivePortalBlockingPageTest : public InProcessBrowserTest { | 67 class CaptivePortalBlockingPageTest : public InProcessBrowserTest { |
49 public: | 68 public: |
50 CaptivePortalBlockingPageTest() {} | 69 CaptivePortalBlockingPageTest() {} |
51 | 70 |
| 71 void TestInterstitial(bool is_wifi_connection, |
| 72 const std::string& wifi_ssid, |
| 73 const GURL& login_url, |
| 74 ExpectWiFi expect_wifi, |
| 75 ExpectWiFiSSID expect_wifi_ssid, |
| 76 ExpectLoginURL expect_login_url, |
| 77 const std::string& expected_login_hostname); |
| 78 |
| 79 void TestInterstitial(bool is_wifi_connection, |
| 80 const std::string& wifi_ssid, |
| 81 const GURL& login_url, |
| 82 ExpectWiFi expect_wifi, |
| 83 ExpectWiFiSSID expect_wifi_ssid, |
| 84 ExpectLoginURL expect_login_url); |
| 85 |
52 private: | 86 private: |
53 DISALLOW_COPY_AND_ASSIGN(CaptivePortalBlockingPageTest); | 87 DISALLOW_COPY_AND_ASSIGN(CaptivePortalBlockingPageTest); |
54 }; | 88 }; |
55 | 89 |
56 // If the connection is not a Wi-Fi connection, the wired network version of the | 90 void CaptivePortalBlockingPageTest::TestInterstitial( |
57 // captive portal interstitial should be displayed. | 91 bool is_wifi_connection, |
58 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, | 92 const std::string& wifi_ssid, |
59 ShowWiredNetworkInterstitial) { | 93 const GURL& login_url, |
60 const GURL kLandingUrl("http://captive.portal/landing_url"); | 94 ExpectWiFi expect_wifi, |
| 95 ExpectWiFiSSID expect_wifi_ssid, |
| 96 ExpectLoginURL expect_login_url, |
| 97 const std::string& expected_login_hostname) { |
61 content::WebContents* contents = | 98 content::WebContents* contents = |
62 browser()->tab_strip_model()->GetActiveWebContents(); | 99 browser()->tab_strip_model()->GetActiveWebContents(); |
63 DCHECK(contents); | 100 DCHECK(contents); |
64 // Blocking page is owned by the interstitial. | 101 // Blocking page is owned by the interstitial. |
65 CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage( | 102 CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage( |
66 contents, GURL(kBrokenSSL), kLandingUrl, base::Callback<void(bool)>()); | 103 contents, GURL(kBrokenSSL), login_url, base::Callback<void(bool)>()); |
67 blocking_page->SetWiFiConnectionForTesting(false); | 104 blocking_page->SetWiFiConnectionForTesting(is_wifi_connection); |
| 105 blocking_page->SetWiFiSSIDForTesting(wifi_ssid); |
68 blocking_page->Show(); | 106 blocking_page->Show(); |
69 | 107 |
70 WaitForInterstitialAttach(contents); | 108 WaitForInterstitialAttach(contents); |
71 EXPECT_TRUE( | 109 EXPECT_TRUE( |
72 WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame())); | 110 WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame())); |
73 EXPECT_FALSE( | 111 EXPECT_EQ(expect_wifi == EXPECT_WIFI_YES, |
74 IsInterstitialDisplayingText(contents->GetInterstitialPage(), "Wi-Fi")); | 112 IsInterstitialDisplayingText(contents->GetInterstitialPage(), |
| 113 "Wi-Fi")); |
| 114 if (!wifi_ssid.empty()) { |
| 115 EXPECT_EQ(expect_wifi_ssid == EXPECT_WIFI_SSID_YES, |
| 116 IsInterstitialDisplayingText(contents->GetInterstitialPage(), |
| 117 wifi_ssid)); |
| 118 } |
| 119 EXPECT_EQ(expect_login_url == EXPECT_LOGIN_URL_YES, |
| 120 IsInterstitialDisplayingText(contents->GetInterstitialPage(), |
| 121 expected_login_hostname)); |
| 122 EXPECT_EQ(expect_login_url == EXPECT_LOGIN_URL_NO, |
| 123 IsInterstitialDisplayingText(contents->GetInterstitialPage(), |
| 124 kGenericLoginURLText)); |
| 125 } |
| 126 |
| 127 void CaptivePortalBlockingPageTest::TestInterstitial( |
| 128 bool is_wifi_connection, |
| 129 const std::string& wifi_ssid, |
| 130 const GURL& login_url, |
| 131 ExpectWiFi expect_wifi, |
| 132 ExpectWiFiSSID expect_wifi_ssid, |
| 133 ExpectLoginURL expect_login_url) { |
| 134 TestInterstitial(is_wifi_connection, wifi_ssid, login_url, |
| 135 expect_wifi, expect_wifi_ssid, expect_login_url, |
| 136 login_url.host()); |
| 137 } |
| 138 |
| 139 // If the connection is not a Wi-Fi connection, the wired network version of the |
| 140 // captive portal interstitial should be displayed. |
| 141 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, |
| 142 WiredNetwork_LoginURL) { |
| 143 TestInterstitial(false, kWiFiSSID, GURL("http://captive.portal/landing_url"), |
| 144 EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_YES); |
| 145 |
| 146 } |
| 147 |
| 148 // Same as above, expect the login URL is the same as the captive portal ping |
| 149 // url (i.e. the portal intercepts requests without using HTTP redirects), in |
| 150 // which case the login URL shouldn't be displayed. |
| 151 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, |
| 152 WiredNetwork_NoLoginURL) { |
| 153 const GURL kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL); |
| 154 TestInterstitial(false, kWiFiSSID, kLandingUrl, |
| 155 EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_NO); |
75 } | 156 } |
76 | 157 |
77 // If the connection is a Wi-Fi connection, the Wi-Fi version of the captive | 158 // If the connection is a Wi-Fi connection, the Wi-Fi version of the captive |
78 // portal interstitial should be displayed. | 159 // portal interstitial should be displayed. |
79 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, | 160 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, |
80 ShowWiFiInterstitial) { | 161 WiFi_SSID_LoginURL) { |
81 const GURL kLandingUrl("http://captive.portal/landing_url"); | 162 TestInterstitial(true, kWiFiSSID, GURL("http://captive.portal/landing_url"), |
82 content::WebContents* contents = | 163 EXPECT_WIFI_YES, EXPECT_WIFI_SSID_YES, EXPECT_LOGIN_URL_YES); |
83 browser()->tab_strip_model()->GetActiveWebContents(); | |
84 DCHECK(contents); | |
85 // Blocking page is owned by the interstitial. | |
86 CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage( | |
87 contents, GURL(kBrokenSSL), kLandingUrl, base::Callback<void(bool)>()); | |
88 blocking_page->SetWiFiConnectionForTesting(true); | |
89 blocking_page->Show(); | |
90 | |
91 WaitForInterstitialAttach(contents); | |
92 EXPECT_TRUE( | |
93 WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame())); | |
94 EXPECT_TRUE( | |
95 IsInterstitialDisplayingText(contents->GetInterstitialPage(), "Wi-Fi")); | |
96 } | 164 } |
97 | 165 |
98 // The captive portal interstitial should show the login url if the login url | 166 // Same as above, with login URL but no SSID. |
99 // is different than the captive portal ping url (i.e. the portal intercepts | |
100 // requests via HTTP redirects). | |
101 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, | 167 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, |
102 ShowLoginDomainIfPortalRedirectsDetectionURL) { | 168 WiFi_NoSSID_LoginURL) { |
103 const GURL kLandingUrl("http://captive.portal/landing_url"); | 169 TestInterstitial(true, "", GURL("http://captive.portal/landing_url"), |
104 content::WebContents* contents = | 170 EXPECT_WIFI_YES, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_YES); |
105 browser()->tab_strip_model()->GetActiveWebContents(); | |
106 DCHECK(contents); | |
107 // Blocking page is owned by the interstitial. | |
108 CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage( | |
109 contents, GURL(kBrokenSSL), kLandingUrl, base::Callback<void(bool)>()); | |
110 blocking_page->SetWiFiConnectionForTesting(false); | |
111 blocking_page->Show(); | |
112 | |
113 WaitForInterstitialAttach(contents); | |
114 EXPECT_TRUE( | |
115 WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame())); | |
116 | |
117 EXPECT_TRUE(IsInterstitialDisplayingText(contents->GetInterstitialPage(), | |
118 kLandingUrl.host())); | |
119 EXPECT_FALSE(IsInterstitialDisplayingText(contents->GetInterstitialPage(), | |
120 kGenericLoginURLText)); | |
121 } | 171 } |
122 | 172 |
123 // The captive portal interstitial should show a generic text if the login url | 173 // Same as above, with SSID but no login URL. |
124 // is the same as the captive portal ping url (i.e. the portal intercepts | |
125 // requests without using HTTP redirects). | |
126 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, | 174 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, |
127 DontShowLoginDomainIfPortalDoesntRedirectDetectionURL) { | 175 WiFi_SSID_NoLoginURL) { |
128 const GURL kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL); | 176 const GURL kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL); |
129 content::WebContents* contents = | 177 TestInterstitial(true, kWiFiSSID, kLandingUrl, |
130 browser()->tab_strip_model()->GetActiveWebContents(); | 178 EXPECT_WIFI_YES, EXPECT_WIFI_SSID_YES, EXPECT_LOGIN_URL_NO); |
131 DCHECK(contents); | |
132 // Blocking page is owned by the interstitial. | |
133 CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage( | |
134 contents, GURL(kBrokenSSL), kLandingUrl, base::Callback<void(bool)>()); | |
135 blocking_page->SetWiFiConnectionForTesting(false); | |
136 blocking_page->Show(); | |
137 | |
138 WaitForInterstitialAttach(contents); | |
139 EXPECT_TRUE( | |
140 WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame())); | |
141 | |
142 EXPECT_FALSE(IsInterstitialDisplayingText(contents->GetInterstitialPage(), | |
143 kLandingUrl.host())); | |
144 EXPECT_TRUE(IsInterstitialDisplayingText(contents->GetInterstitialPage(), | |
145 kGenericLoginURLText)); | |
146 } | 179 } |
147 | 180 |
148 class CaptivePortalBlockingPageIDNTest : public InProcessBrowserTest { | 181 // Same as above, with no SSID and no login URL. |
| 182 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest, |
| 183 WiFi_NoSSID_NoLoginURL) { |
| 184 const GURL kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL); |
| 185 TestInterstitial(true, "", kLandingUrl, |
| 186 EXPECT_WIFI_YES, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_NO); |
| 187 } |
| 188 |
| 189 class CaptivePortalBlockingPageIDNTest : public CaptivePortalBlockingPageTest { |
149 public: | 190 public: |
150 // InProcessBrowserTest: | 191 // InProcessBrowserTest: |
151 void SetUpOnMainThread() override { | 192 void SetUpOnMainThread() override { |
152 // Clear AcceptLanguages to force punycode decoding. | 193 // Clear AcceptLanguages to force punycode decoding. |
153 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages, | 194 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages, |
154 std::string()); | 195 std::string()); |
155 } | 196 } |
156 }; | 197 }; |
157 | 198 |
158 // Same as ShowLoginDomainIfPortalRedirectsDetectionURL, except the login | 199 // Same as CaptivePortalBlockingPageTest.WiredNetwork_LoginURL, except the login |
159 // domain is an IDN. | 200 // domain is an IDN. |
160 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageIDNTest, | 201 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageIDNTest, |
161 ShowLoginIDNIfPortalRedirectsDetectionURL) { | 202 ShowLoginIDNIfPortalRedirectsDetectionURL) { |
162 const char kHostname[] = | 203 const char kHostname[] = |
163 "xn--d1abbgf6aiiy.xn--p1ai"; | 204 "xn--d1abbgf6aiiy.xn--p1ai"; |
164 const char kHostnameJSUnicode[] = | 205 const char kHostnameJSUnicode[] = |
165 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442." | 206 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442." |
166 "\\u0440\\u0444"; | 207 "\\u0440\\u0444"; |
167 std::string landing_url_spec = | 208 std::string landing_url_spec = |
168 base::StringPrintf("http://%s/landing_url", kHostname); | 209 base::StringPrintf("http://%s/landing_url", kHostname); |
169 GURL landing_url(landing_url_spec); | 210 GURL landing_url(landing_url_spec); |
170 | 211 |
171 content::WebContents* contents = | 212 TestInterstitial(false, kWiFiSSID, landing_url, |
172 browser()->tab_strip_model()->GetActiveWebContents(); | 213 EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_YES, |
173 DCHECK(contents); | 214 kHostnameJSUnicode); |
174 // Blocking page is owned by the interstitial. | |
175 CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage( | |
176 contents, GURL(kBrokenSSL), landing_url, base::Callback<void(bool)>()); | |
177 blocking_page->SetWiFiConnectionForTesting(false); | |
178 blocking_page->Show(); | |
179 | |
180 WaitForInterstitialAttach(contents); | |
181 EXPECT_TRUE( | |
182 WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame())); | |
183 | |
184 EXPECT_TRUE(IsInterstitialDisplayingText(contents->GetInterstitialPage(), | |
185 kHostnameJSUnicode)); | |
186 EXPECT_FALSE(IsInterstitialDisplayingText(contents->GetInterstitialPage(), | |
187 kGenericLoginURLText)); | |
188 } | 215 } |
OLD | NEW |