1 // Copyright 2014 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 "base/command_line.h"
6 #include "base/prefs/pref_service.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/values.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/common/cancelable_request.h"
11 #include "chrome/browser/history/history_service_factory.h"
12 #include "chrome/browser/infobars/infobar_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/supervised_user/supervised_user_constants.h"
15 #include "chrome/browser/supervised_user/supervised_user_interstitial.h"
16 #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
17 #include "chrome/browser/supervised_user/supervised_user_service.h"
18 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
19 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
20 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_navigator.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/test/base/in_process_browser_test.h"
28 #include "chrome/test/base/ui_test_utils.h"
29 #include "components/infobars/core/confirm_infobar_delegate.h"
30 #include "components/infobars/core/infobar.h"
31 #include "components/pref_registry/pref_registry_syncable.h"
32 #include "content/public/browser/interstitial_page.h"
33 #include "content/public/browser/navigation_controller.h"
34 #include "content/public/browser/navigation_entry.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_observer.h"
38 #include "content/public/test/browser_test_utils.h"
39 #include "grit/generated_resources.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "ui/base/l10n/l10n_util.h"
42
43 using content::InterstitialPage;
44 using content::NavigationController;
45 using content::NavigationEntry;
46 using content::WebContents;
47
48 namespace {
49
50 // Tests the filter mode in which all sites are blocked by default.
51 class SupervisedUserBlockModeTest : public InProcessBrowserTest {
52 public:
53 // Indicates whether the interstitial should proceed or not.
54 enum InterstitialAction {
55 INTERSTITIAL_PROCEED,
56 INTERSTITIAL_DONTPROCEED,
57 };
58
SupervisedUserBlockModeTest()59 SupervisedUserBlockModeTest() : supervised_user_service_(NULL) {}
~SupervisedUserBlockModeTest()60 virtual ~SupervisedUserBlockModeTest() {}
61
CheckShownPageIsInterstitial(WebContents * tab)62 void CheckShownPageIsInterstitial(WebContents* tab) {
63 CheckShownPage(tab, content::PAGE_TYPE_INTERSTITIAL);
64 }
65
CheckShownPageIsNotInterstitial(WebContents * tab)66 void CheckShownPageIsNotInterstitial(WebContents* tab) {
67 CheckShownPage(tab, content::PAGE_TYPE_NORMAL);
68 }
69
70 // Checks to see if the type of the current page is |page_type|.
CheckShownPage(WebContents * tab,content::PageType page_type)71 void CheckShownPage(WebContents* tab, content::PageType page_type) {
72 ASSERT_FALSE(tab->IsCrashed());
73 NavigationEntry* entry = tab->GetController().GetActiveEntry();
74 ASSERT_TRUE(entry);
75 ASSERT_EQ(page_type, entry->GetPageType());
76 }
77
SendAccessRequest(WebContents * tab)78 void SendAccessRequest(WebContents* tab) {
79 InterstitialPage* interstitial_page = tab->GetInterstitialPage();
80 ASSERT_TRUE(interstitial_page);
81
82 // Get the SupervisedUserInterstitial delegate.
83 content::InterstitialPageDelegate* delegate =
84 interstitial_page->GetDelegateForTesting();
85
86 // Simulate the click on the "request" button.
87 delegate->CommandReceived("\"request\"");
88 }
89
GoBack(WebContents * tab)90 void GoBack(WebContents* tab) {
91 InterstitialPage* interstitial_page = tab->GetInterstitialPage();
92 ASSERT_TRUE(interstitial_page);
93
94 // Get the SupervisedUserInterstitial delegate.
95 content::InterstitialPageDelegate* delegate =
96 interstitial_page->GetDelegateForTesting();
97
98 // Simulate the click on the "back" button.
99 delegate->CommandReceived("\"back\"");
100 }
101
102 protected:
SetUpOnMainThread()103 virtual void SetUpOnMainThread() OVERRIDE {
104 // Set up the SupervisedUserNavigationObserver manually since the profile
105 // was not supervised when the browser was created.
106 content::WebContents* web_contents =
107 browser()->tab_strip_model()->GetActiveWebContents();
108 SupervisedUserNavigationObserver::CreateForWebContents(web_contents);
109
110 Profile* profile = browser()->profile();
111 supervised_user_service_ =
112 SupervisedUserServiceFactory::GetForProfile(profile);
113 SupervisedUserSettingsService* supervised_user_settings_service =
114 SupervisedUserSettingsServiceFactory::GetForProfile(profile);
115 supervised_user_settings_service->SetLocalSettingForTesting(
116 supervised_users::kContentPackDefaultFilteringBehavior,
117 scoped_ptr<base::Value>(
118 new base::FundamentalValue(SupervisedUserURLFilter::BLOCK)));
119 }
120
SetUpCommandLine(CommandLine * command_line)121 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
122 // Enable the test server and remap all URLs to it.
123 ASSERT_TRUE(test_server()->Start());
124 std::string host_port = test_server()->host_port_pair().ToString();
125 command_line->AppendSwitchASCII(switches::kHostResolverRules,
126 "MAP *.example.com " + host_port + "," +
127 "MAP *.new-example.com " + host_port + "," +
128 "MAP *.a.com " + host_port);
129
130 command_line->AppendSwitchASCII(switches::kSupervisedUserId, "asdf");
131 }
132
133 // Acts like a synchronous call to history's QueryHistory. Modified from
134 // history_querying_unittest.cc.
QueryHistory(HistoryService * history_service,const std::string & text_query,const history::QueryOptions & options,history::QueryResults * results)135 void QueryHistory(HistoryService* history_service,
136 const std::string& text_query,
137 const history::QueryOptions& options,
138 history::QueryResults* results) {
139 CancelableRequestConsumer history_request_consumer;
140 base::RunLoop run_loop;
141 history_service->QueryHistory(
142 base::UTF8ToUTF16(text_query),
143 options,
144 &history_request_consumer,
145 base::Bind(&SupervisedUserBlockModeTest::QueryHistoryComplete,
146 base::Unretained(this),
147 results,
148 &run_loop));
149 run_loop.Run(); // Will go until ...Complete calls Quit.
150 }
151
QueryHistoryComplete(history::QueryResults * new_results,base::RunLoop * run_loop,HistoryService::Handle,history::QueryResults * results)152 void QueryHistoryComplete(history::QueryResults* new_results,
153 base::RunLoop* run_loop,
154 HistoryService::Handle /* handle */,
155 history::QueryResults* results) {
156 results->Swap(new_results);
157 run_loop->Quit(); // Will return out to QueryHistory.
158 }
159
160 SupervisedUserService* supervised_user_service_;
161 };
162
163 class MockTabStripModelObserver : public TabStripModelObserver {
164 public:
MockTabStripModelObserver(TabStripModel * tab_strip)165 explicit MockTabStripModelObserver(TabStripModel* tab_strip)
166 : tab_strip_(tab_strip) {
167 tab_strip_->AddObserver(this);
168 }
169
~MockTabStripModelObserver()170 ~MockTabStripModelObserver() {
171 tab_strip_->RemoveObserver(this);
172 }
173
174 MOCK_METHOD3(TabClosingAt, void(TabStripModel*, content::WebContents*, int));
175
176 private:
177 TabStripModel* tab_strip_;
178 };
179
180 // Navigates to a blocked URL.
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,SendAccessRequestOnBlockedURL)181 IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,
182 SendAccessRequestOnBlockedURL) {
183 GURL test_url("http://www.example.com/files/simple.html");
184 ui_test_utils::NavigateToURL(browser(), test_url);
185
186 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
187
188 CheckShownPageIsInterstitial(tab);
189
190 SendAccessRequest(tab);
191
192 // TODO(sergiu): Properly check that the access request was sent here.
193
194 GoBack(tab);
195
196 // Make sure that the tab is still there.
197 EXPECT_EQ(tab, browser()->tab_strip_model()->GetActiveWebContents());
198
199 CheckShownPageIsNotInterstitial(tab);
200 }
201
202 // Navigates to a blocked URL in a new tab. We expect the tab to be closed
203 // automatically on pressing the "back" button on the interstitial.
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,OpenBlockedURLInNewTab)204 IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest, OpenBlockedURLInNewTab) {
205 TabStripModel* tab_strip = browser()->tab_strip_model();
206 WebContents* prev_tab = tab_strip->GetActiveWebContents();
207
208 // Open blocked URL in a new tab.
209 GURL test_url("http://www.example.com/files/simple.html");
210 ui_test_utils::NavigateToURLWithDisposition(
211 browser(), test_url, NEW_FOREGROUND_TAB,
212 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
213
214 // Check that we got the interstitial.
215 WebContents* tab = tab_strip->GetActiveWebContents();
216 CheckShownPageIsInterstitial(tab);
217
218 // On pressing the "back" button, the new tab should be closed, and we should
219 // get back to the previous active tab.
220 MockTabStripModelObserver observer(tab_strip);
221 EXPECT_CALL(observer,
222 TabClosingAt(tab_strip, tab, tab_strip->active_index()));
223 GoBack(tab);
224 EXPECT_EQ(prev_tab, tab_strip->GetActiveWebContents());
225 }
226
227 // Tests whether a visit attempt adds a special history entry.
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,HistoryVisitRecorded)228 IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,
229 HistoryVisitRecorded) {
230 GURL allowed_url("http://www.example.com/files/simple.html");
231
232 // Set the host as allowed.
233 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
234 dict->SetBooleanWithoutPathExpansion(allowed_url.host(), true);
235 SupervisedUserSettingsService* supervised_user_settings_service =
236 SupervisedUserSettingsServiceFactory::GetForProfile(
237 browser()->profile());
238 supervised_user_settings_service->SetLocalSettingForTesting(
239 supervised_users::kContentPackManualBehaviorHosts,
240 dict.PassAs<base::Value>());
241 EXPECT_EQ(
242 SupervisedUserService::MANUAL_ALLOW,
243 supervised_user_service_->GetManualBehaviorForHost(allowed_url.host()));
244
245 ui_test_utils::NavigateToURL(browser(), allowed_url);
246
247 // Navigate to it and check that we don't get an interstitial.
248 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
249 CheckShownPageIsNotInterstitial(tab);
250
251 // Navigate to a blocked page and go back on the interstitial.
252 GURL blocked_url("http://www.new-example.com/files/simple.html");
253 ui_test_utils::NavigateToURL(browser(), blocked_url);
254
255 tab = browser()->tab_strip_model()->GetActiveWebContents();
256
257 CheckShownPageIsInterstitial(tab);
258 GoBack(tab);
259
260 // Check that we went back to the first URL and that the manual behaviors
261 // have not changed.
262 EXPECT_EQ(allowed_url.spec(), tab->GetURL().spec());
263 EXPECT_EQ(SupervisedUserService::MANUAL_ALLOW,
264 supervised_user_service_->GetManualBehaviorForHost(
265 "www.example.com"));
266 EXPECT_EQ(
267 SupervisedUserService::MANUAL_NONE,
268 supervised_user_service_->GetManualBehaviorForHost(
269 "www.new-example.com"));
270
271 // Query the history entry.
272 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
273 browser()->profile(), Profile::EXPLICIT_ACCESS);
274 history::QueryOptions options;
275 history::QueryResults results;
276 QueryHistory(history_service, "", options, &results);
277
278 // Check that the entries have the correct blocked_visit value.
279 ASSERT_EQ(2u, results.size());
280 EXPECT_EQ(blocked_url.spec(), results[0].url().spec());
281 EXPECT_TRUE(results[0].blocked_visit());
282 EXPECT_EQ(allowed_url.spec(), results[1].url().spec());
283 EXPECT_FALSE(results[1].blocked_visit());
284 }
285
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,Unblock)286 IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest, Unblock) {
287 GURL test_url("http://www.example.com/files/simple.html");
288 ui_test_utils::NavigateToURL(browser(), test_url);
289
290 WebContents* web_contents =
291 browser()->tab_strip_model()->GetActiveWebContents();
292
293 CheckShownPageIsInterstitial(web_contents);
294
295 content::WindowedNotificationObserver observer(
296 content::NOTIFICATION_LOAD_STOP,
297 content::NotificationService::AllSources());
298
299 // Set the host as allowed.
300 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
301 dict->SetBooleanWithoutPathExpansion(test_url.host(), true);
302 SupervisedUserSettingsService* supervised_user_settings_service =
303 SupervisedUserSettingsServiceFactory::GetForProfile(
304 browser()->profile());
305 supervised_user_settings_service->SetLocalSettingForTesting(
306 supervised_users::kContentPackManualBehaviorHosts,
307 dict.PassAs<base::Value>());
308 EXPECT_EQ(
309 SupervisedUserService::MANUAL_ALLOW,
310 supervised_user_service_->GetManualBehaviorForHost(test_url.host()));
311
312 observer.Wait();
313 EXPECT_EQ(test_url, web_contents->GetURL());
314 }
315
316 } // namespace
317