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/path_service.h"
6#include "base/prefs/pref_service.h"
7#include "base/prefs/scoped_user_pref_update.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/extensions/extension_service.h"
11#include "chrome/browser/extensions/extension_service_test_base.h"
12#include "chrome/browser/extensions/unpacked_installer.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
15#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
16#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17#include "chrome/browser/supervised_user/custodian_profile_downloader_service.h"
18#include "chrome/browser/supervised_user/custodian_profile_downloader_service_factory.h"
19#include "chrome/browser/supervised_user/supervised_user_service.h"
20#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
21#include "chrome/browser/ui/browser_list.h"
22#include "chrome/common/chrome_paths.h"
23#include "chrome/common/extensions/features/feature_channel.h"
24#include "chrome/common/pref_names.h"
25#include "chrome/test/base/testing_profile.h"
26#include "content/public/test/test_browser_thread_bundle.h"
27#include "content/public/test/test_utils.h"
28#include "extensions/common/extension.h"
29#include "extensions/common/extension_builder.h"
30#include "extensions/common/manifest_constants.h"
31#include "testing/gtest/include/gtest/gtest.h"
32
33using content::MessageLoopRunner;
34
35namespace {
36
37void OnProfileDownloadedFail(const base::string16& full_name) {
38  ASSERT_TRUE(false) << "Profile download should not have succeeded.";
39}
40
41class SupervisedUserURLFilterObserver :
42    public SupervisedUserURLFilter::Observer {
43 public:
44  explicit SupervisedUserURLFilterObserver(SupervisedUserURLFilter* url_filter)
45      : url_filter_(url_filter) {
46    Reset();
47    url_filter_->AddObserver(this);
48  }
49
50  ~SupervisedUserURLFilterObserver() {
51    url_filter_->RemoveObserver(this);
52  }
53
54  void Wait() {
55    message_loop_runner_->Run();
56    Reset();
57  }
58
59  // SupervisedUserURLFilter::Observer
60  virtual void OnSiteListUpdated() OVERRIDE {
61    message_loop_runner_->Quit();
62  }
63
64 private:
65  void Reset() {
66    message_loop_runner_ = new MessageLoopRunner;
67  }
68
69  SupervisedUserURLFilter* url_filter_;
70  scoped_refptr<MessageLoopRunner> message_loop_runner_;
71};
72
73class SupervisedUserServiceTest : public ::testing::Test {
74 public:
75  SupervisedUserServiceTest() {}
76
77  virtual void SetUp() OVERRIDE {
78    TestingProfile::Builder builder;
79    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
80                              BuildFakeProfileOAuth2TokenService);
81    profile_ = builder.Build();
82    supervised_user_service_ =
83        SupervisedUserServiceFactory::GetForProfile(profile_.get());
84  }
85
86  virtual void TearDown() OVERRIDE {
87    profile_.reset();
88  }
89
90  virtual ~SupervisedUserServiceTest() {}
91
92 protected:
93  content::TestBrowserThreadBundle thread_bundle_;
94  scoped_ptr<TestingProfile> profile_;
95  SupervisedUserService* supervised_user_service_;
96};
97
98}  // namespace
99
100TEST_F(SupervisedUserServiceTest, GetManualExceptionsForHost) {
101  GURL kExampleFooURL("http://www.example.com/foo");
102  GURL kExampleBarURL("http://www.example.com/bar");
103  GURL kExampleFooNoWWWURL("http://example.com/foo");
104  GURL kBlurpURL("http://blurp.net/bla");
105  GURL kMooseURL("http://moose.org/baz");
106  {
107    DictionaryPrefUpdate update(profile_->GetPrefs(),
108                                prefs::kSupervisedUserManualURLs);
109    base::DictionaryValue* dict = update.Get();
110    dict->SetBooleanWithoutPathExpansion(kExampleFooURL.spec(), true);
111    dict->SetBooleanWithoutPathExpansion(kExampleBarURL.spec(), false);
112    dict->SetBooleanWithoutPathExpansion(kExampleFooNoWWWURL.spec(), true);
113    dict->SetBooleanWithoutPathExpansion(kBlurpURL.spec(), true);
114  }
115
116  EXPECT_EQ(SupervisedUserService::MANUAL_ALLOW,
117            supervised_user_service_->GetManualBehaviorForURL(kExampleFooURL));
118  EXPECT_EQ(SupervisedUserService::MANUAL_BLOCK,
119            supervised_user_service_->GetManualBehaviorForURL(kExampleBarURL));
120  EXPECT_EQ(SupervisedUserService::MANUAL_ALLOW,
121            supervised_user_service_->GetManualBehaviorForURL(
122                kExampleFooNoWWWURL));
123  EXPECT_EQ(SupervisedUserService::MANUAL_ALLOW,
124            supervised_user_service_->GetManualBehaviorForURL(kBlurpURL));
125  EXPECT_EQ(SupervisedUserService::MANUAL_NONE,
126            supervised_user_service_->GetManualBehaviorForURL(kMooseURL));
127  std::vector<GURL> exceptions;
128  supervised_user_service_->GetManualExceptionsForHost("www.example.com",
129                                                       &exceptions);
130  ASSERT_EQ(2u, exceptions.size());
131  EXPECT_EQ(kExampleBarURL, exceptions[0]);
132  EXPECT_EQ(kExampleFooURL, exceptions[1]);
133
134  {
135    DictionaryPrefUpdate update(profile_->GetPrefs(),
136                                prefs::kSupervisedUserManualURLs);
137    base::DictionaryValue* dict = update.Get();
138    for (std::vector<GURL>::iterator it = exceptions.begin();
139         it != exceptions.end(); ++it) {
140      dict->RemoveWithoutPathExpansion(it->spec(), NULL);
141    }
142  }
143
144  EXPECT_EQ(SupervisedUserService::MANUAL_NONE,
145            supervised_user_service_->GetManualBehaviorForURL(kExampleFooURL));
146  EXPECT_EQ(SupervisedUserService::MANUAL_NONE,
147            supervised_user_service_->GetManualBehaviorForURL(kExampleBarURL));
148  EXPECT_EQ(SupervisedUserService::MANUAL_ALLOW,
149            supervised_user_service_->GetManualBehaviorForURL(
150                kExampleFooNoWWWURL));
151  EXPECT_EQ(SupervisedUserService::MANUAL_ALLOW,
152            supervised_user_service_->GetManualBehaviorForURL(kBlurpURL));
153  EXPECT_EQ(SupervisedUserService::MANUAL_NONE,
154            supervised_user_service_->GetManualBehaviorForURL(kMooseURL));
155}
156
157// Ensure that the CustodianProfileDownloaderService shuts down cleanly. If no
158// DCHECK is hit when the service is destroyed, this test passed.
159TEST_F(SupervisedUserServiceTest, ShutDownCustodianProfileDownloader) {
160  CustodianProfileDownloaderService* downloader_service =
161      CustodianProfileDownloaderServiceFactory::GetForProfile(profile_.get());
162
163  // Emulate being logged in, then start to download a profile so a
164  // ProfileDownloader gets created.
165  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "Logged In");
166  downloader_service->DownloadProfile(base::Bind(&OnProfileDownloadedFail));
167}
168
169#if !defined(OS_ANDROID)
170class SupervisedUserServiceExtensionTestBase
171    : public extensions::ExtensionServiceTestBase {
172 public:
173  explicit SupervisedUserServiceExtensionTestBase(bool is_supervised)
174      : is_supervised_(is_supervised),
175        channel_(chrome::VersionInfo::CHANNEL_DEV) {}
176  virtual ~SupervisedUserServiceExtensionTestBase() {}
177
178  virtual void SetUp() OVERRIDE {
179    ExtensionServiceTestBase::SetUp();
180    ExtensionServiceTestBase::ExtensionServiceInitParams params =
181        CreateDefaultInitParams();
182    params.profile_is_supervised = is_supervised_;
183    InitializeExtensionService(params);
184    SupervisedUserServiceFactory::GetForProfile(profile_.get())->Init();
185  }
186
187 protected:
188  ScopedVector<SupervisedUserSiteList> GetActiveSiteLists(
189      SupervisedUserService* supervised_user_service) {
190    return supervised_user_service->GetActiveSiteLists();
191  }
192
193  scoped_refptr<extensions::Extension> MakeThemeExtension() {
194    scoped_ptr<base::DictionaryValue> source(new base::DictionaryValue());
195    source->SetString(extensions::manifest_keys::kName, "Theme");
196    source->Set(extensions::manifest_keys::kTheme, new base::DictionaryValue());
197    source->SetString(extensions::manifest_keys::kVersion, "1.0");
198    extensions::ExtensionBuilder builder;
199    scoped_refptr<extensions::Extension> extension =
200        builder.SetManifest(source.Pass()).Build();
201    return extension;
202  }
203
204  scoped_refptr<extensions::Extension> MakeExtension(bool by_custodian) {
205    scoped_ptr<base::DictionaryValue> manifest = extensions::DictionaryBuilder()
206      .Set(extensions::manifest_keys::kName, "Extension")
207      .Set(extensions::manifest_keys::kVersion, "1.0")
208      .Build();
209    int creation_flags = extensions::Extension::NO_FLAGS;
210    if (by_custodian)
211      creation_flags |= extensions::Extension::WAS_INSTALLED_BY_CUSTODIAN;
212    extensions::ExtensionBuilder builder;
213    scoped_refptr<extensions::Extension> extension =
214        builder.SetManifest(manifest.Pass()).AddFlags(creation_flags).Build();
215    return extension;
216  }
217
218  bool is_supervised_;
219  extensions::ScopedCurrentChannel channel_;
220};
221
222class SupervisedUserServiceExtensionTestUnsupervised
223    : public SupervisedUserServiceExtensionTestBase {
224 public:
225  SupervisedUserServiceExtensionTestUnsupervised()
226      : SupervisedUserServiceExtensionTestBase(false) {}
227};
228
229class SupervisedUserServiceExtensionTest
230    : public SupervisedUserServiceExtensionTestBase {
231 public:
232  SupervisedUserServiceExtensionTest()
233      : SupervisedUserServiceExtensionTestBase(true) {}
234};
235
236TEST_F(SupervisedUserServiceExtensionTestUnsupervised,
237       ExtensionManagementPolicyProvider) {
238  SupervisedUserService* supervised_user_service =
239      SupervisedUserServiceFactory::GetForProfile(profile_.get());
240  EXPECT_FALSE(profile_->IsSupervised());
241
242  scoped_refptr<extensions::Extension> extension = MakeExtension(false);
243  base::string16 error_1;
244  EXPECT_TRUE(supervised_user_service->UserMayLoad(extension.get(), &error_1));
245  EXPECT_EQ(base::string16(), error_1);
246
247  base::string16 error_2;
248  EXPECT_TRUE(
249      supervised_user_service->UserMayModifySettings(extension.get(),
250                                                     &error_2));
251  EXPECT_EQ(base::string16(), error_2);
252}
253
254TEST_F(SupervisedUserServiceExtensionTest, ExtensionManagementPolicyProvider) {
255  SupervisedUserService* supervised_user_service =
256      SupervisedUserServiceFactory::GetForProfile(profile_.get());
257  SupervisedUserURLFilterObserver observer(
258      supervised_user_service->GetURLFilterForUIThread());
259  ASSERT_TRUE(profile_->IsSupervised());
260  // Wait for the initial update to finish (otherwise we'll get leaks).
261  observer.Wait();
262
263  // Check that a supervised user can install a theme.
264  scoped_refptr<extensions::Extension> theme = MakeThemeExtension();
265  base::string16 error_1;
266  EXPECT_TRUE(supervised_user_service->UserMayLoad(theme.get(), &error_1));
267  EXPECT_TRUE(error_1.empty());
268  EXPECT_TRUE(
269      supervised_user_service->UserMayModifySettings(theme.get(), &error_1));
270  EXPECT_TRUE(error_1.empty());
271
272  // Now check a different kind of extension.
273  scoped_refptr<extensions::Extension> extension = MakeExtension(false);
274  EXPECT_FALSE(supervised_user_service->UserMayLoad(extension.get(), &error_1));
275  EXPECT_FALSE(error_1.empty());
276
277  base::string16 error_2;
278  EXPECT_FALSE(supervised_user_service->UserMayModifySettings(extension.get(),
279                                                              &error_2));
280  EXPECT_FALSE(error_2.empty());
281
282  // Check that an extension that was installed by the custodian may be loaded.
283  base::string16 error_3;
284  scoped_refptr<extensions::Extension> extension_2 = MakeExtension(true);
285  EXPECT_TRUE(supervised_user_service->UserMayLoad(extension_2.get(),
286                                                   &error_3));
287  EXPECT_TRUE(error_3.empty());
288
289  // The supervised user should still not be able to uninstall or disable the
290  // extension.
291  base::string16 error_4;
292  EXPECT_FALSE(supervised_user_service->UserMayModifySettings(extension_2.get(),
293                                                              &error_4));
294  EXPECT_FALSE(error_4.empty());
295
296#ifndef NDEBUG
297  EXPECT_FALSE(supervised_user_service->GetDebugPolicyProviderName().empty());
298#endif
299}
300
301TEST_F(SupervisedUserServiceExtensionTest, NoContentPacks) {
302  SupervisedUserService* supervised_user_service =
303      SupervisedUserServiceFactory::GetForProfile(profile_.get());
304  SupervisedUserURLFilter* url_filter =
305      supervised_user_service->GetURLFilterForUIThread();
306
307  GURL url("http://youtube.com");
308  ScopedVector<SupervisedUserSiteList> site_lists =
309      GetActiveSiteLists(supervised_user_service);
310  ASSERT_EQ(0u, site_lists.size());
311  EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
312            url_filter->GetFilteringBehaviorForURL(url));
313}
314
315TEST_F(SupervisedUserServiceExtensionTest, InstallContentPacks) {
316  SupervisedUserService* supervised_user_service =
317      SupervisedUserServiceFactory::GetForProfile(profile_.get());
318  SupervisedUserURLFilter* url_filter =
319      supervised_user_service->GetURLFilterForUIThread();
320  SupervisedUserURLFilterObserver observer(url_filter);
321  observer.Wait();
322
323  GURL example_url("http://example.com");
324  GURL moose_url("http://moose.org");
325  EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
326            url_filter->GetFilteringBehaviorForURL(example_url));
327
328  profile_->GetPrefs()->SetInteger(
329      prefs::kDefaultSupervisedUserFilteringBehavior,
330      SupervisedUserURLFilter::BLOCK);
331  EXPECT_EQ(SupervisedUserURLFilter::BLOCK,
332            url_filter->GetFilteringBehaviorForURL(example_url));
333
334  profile_->GetPrefs()->SetInteger(
335      prefs::kDefaultSupervisedUserFilteringBehavior,
336      SupervisedUserURLFilter::WARN);
337  EXPECT_EQ(SupervisedUserURLFilter::WARN,
338            url_filter->GetFilteringBehaviorForURL(example_url));
339
340  supervised_user_service->set_elevated_for_testing(true);
341
342  // Load a content pack.
343  scoped_refptr<extensions::UnpackedInstaller> installer(
344      extensions::UnpackedInstaller::Create(service_));
345  installer->set_prompt_for_plugins(false);
346  base::FilePath test_data_dir;
347  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
348  base::FilePath extension_path =
349      test_data_dir.AppendASCII("extensions/supervised_user/content_pack");
350  content::WindowedNotificationObserver extension_load_observer(
351      extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
352      content::Source<Profile>(profile_.get()));
353  installer->Load(extension_path);
354  extension_load_observer.Wait();
355  observer.Wait();
356  content::Details<extensions::Extension> details =
357      extension_load_observer.details();
358  scoped_refptr<extensions::Extension> extension =
359      make_scoped_refptr(details.ptr());
360  ASSERT_TRUE(extension.get());
361
362  ScopedVector<SupervisedUserSiteList> site_lists =
363      GetActiveSiteLists(supervised_user_service);
364  ASSERT_EQ(1u, site_lists.size());
365  std::vector<SupervisedUserSiteList::Site> sites;
366  site_lists[0]->GetSites(&sites);
367  ASSERT_EQ(3u, sites.size());
368  EXPECT_EQ(base::ASCIIToUTF16("YouTube"), sites[0].name);
369  EXPECT_EQ(base::ASCIIToUTF16("Homestar Runner"), sites[1].name);
370  EXPECT_EQ(base::string16(), sites[2].name);
371
372  EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
373            url_filter->GetFilteringBehaviorForURL(example_url));
374  EXPECT_EQ(SupervisedUserURLFilter::WARN,
375            url_filter->GetFilteringBehaviorForURL(moose_url));
376
377  // Load a second content pack.
378  installer = extensions::UnpackedInstaller::Create(service_);
379  extension_path =
380      test_data_dir.AppendASCII("extensions/supervised_user/content_pack_2");
381  installer->Load(extension_path);
382  observer.Wait();
383
384  site_lists = GetActiveSiteLists(supervised_user_service);
385  ASSERT_EQ(2u, site_lists.size());
386  sites.clear();
387  site_lists[0]->GetSites(&sites);
388  site_lists[1]->GetSites(&sites);
389  ASSERT_EQ(4u, sites.size());
390  // The site lists might be returned in any order, so we put them into a set.
391  std::set<std::string> site_names;
392  for (std::vector<SupervisedUserSiteList::Site>::const_iterator it =
393      sites.begin(); it != sites.end(); ++it) {
394    site_names.insert(base::UTF16ToUTF8(it->name));
395  }
396  EXPECT_TRUE(site_names.count("YouTube") == 1u);
397  EXPECT_TRUE(site_names.count("Homestar Runner") == 1u);
398  EXPECT_TRUE(site_names.count(std::string()) == 1u);
399  EXPECT_TRUE(site_names.count("Moose") == 1u);
400
401  EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
402            url_filter->GetFilteringBehaviorForURL(example_url));
403  EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
404            url_filter->GetFilteringBehaviorForURL(moose_url));
405
406  // Disable the first content pack.
407  service_->DisableExtension(extension->id(),
408                             extensions::Extension::DISABLE_USER_ACTION);
409  observer.Wait();
410
411  site_lists = GetActiveSiteLists(supervised_user_service);
412  ASSERT_EQ(1u, site_lists.size());
413  sites.clear();
414  site_lists[0]->GetSites(&sites);
415  ASSERT_EQ(1u, sites.size());
416  EXPECT_EQ(base::ASCIIToUTF16("Moose"), sites[0].name);
417
418  EXPECT_EQ(SupervisedUserURLFilter::WARN,
419            url_filter->GetFilteringBehaviorForURL(example_url));
420  EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
421            url_filter->GetFilteringBehaviorForURL(moose_url));
422}
423#endif  // !defined(OS_ANDROID)
424