// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/path_service.h" #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service_unittest.h" #include "chrome/browser/extensions/unpacked_installer.h" #include "chrome/browser/managed_mode/custodian_profile_downloader_service.h" #include "chrome/browser/managed_mode/custodian_profile_downloader_service_factory.h" #include "chrome/browser/managed_mode/managed_user_service.h" #include "chrome/browser/managed_mode/managed_user_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/fake_profile_oauth2_token_service.h" #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/features/feature_channel.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "extensions/common/manifest_constants.h" #include "testing/gtest/include/gtest/gtest.h" using content::MessageLoopRunner; namespace { void OnProfileDownloadedFail(const base::string16& full_name) { ASSERT_TRUE(false) << "Profile download should not have succeeded."; } class ManagedModeURLFilterObserver : public ManagedModeURLFilter::Observer { public: explicit ManagedModeURLFilterObserver(ManagedModeURLFilter* url_filter) : url_filter_(url_filter) { Reset(); url_filter_->AddObserver(this); } ~ManagedModeURLFilterObserver() { url_filter_->RemoveObserver(this); } void Wait() { message_loop_runner_->Run(); Reset(); } // ManagedModeURLFilter::Observer virtual void OnSiteListUpdated() OVERRIDE { message_loop_runner_->Quit(); } private: void Reset() { message_loop_runner_ = new MessageLoopRunner; } ManagedModeURLFilter* url_filter_; scoped_refptr message_loop_runner_; }; class ManagedUserServiceTest : public ::testing::Test { public: ManagedUserServiceTest() {} virtual void SetUp() OVERRIDE { TestingProfile::Builder builder; builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), BuildFakeProfileOAuth2TokenService); profile_ = builder.Build(); managed_user_service_ = ManagedUserServiceFactory::GetForProfile(profile_.get()); } virtual void TearDown() OVERRIDE { profile_.reset(); } virtual ~ManagedUserServiceTest() {} protected: content::TestBrowserThreadBundle thread_bundle_; scoped_ptr profile_; ManagedUserService* managed_user_service_; }; } // namespace TEST_F(ManagedUserServiceTest, GetManualExceptionsForHost) { GURL kExampleFooURL("http://www.example.com/foo"); GURL kExampleBarURL("http://www.example.com/bar"); GURL kExampleFooNoWWWURL("http://example.com/foo"); GURL kBlurpURL("http://blurp.net/bla"); GURL kMooseURL("http://moose.org/baz"); { DictionaryPrefUpdate update(profile_->GetPrefs(), prefs::kManagedModeManualURLs); base::DictionaryValue* dict = update.Get(); dict->SetBooleanWithoutPathExpansion(kExampleFooURL.spec(), true); dict->SetBooleanWithoutPathExpansion(kExampleBarURL.spec(), false); dict->SetBooleanWithoutPathExpansion(kExampleFooNoWWWURL.spec(), true); dict->SetBooleanWithoutPathExpansion(kBlurpURL.spec(), true); } EXPECT_EQ(ManagedUserService::MANUAL_ALLOW, managed_user_service_->GetManualBehaviorForURL(kExampleFooURL)); EXPECT_EQ(ManagedUserService::MANUAL_BLOCK, managed_user_service_->GetManualBehaviorForURL(kExampleBarURL)); EXPECT_EQ(ManagedUserService::MANUAL_ALLOW, managed_user_service_->GetManualBehaviorForURL( kExampleFooNoWWWURL)); EXPECT_EQ(ManagedUserService::MANUAL_ALLOW, managed_user_service_->GetManualBehaviorForURL(kBlurpURL)); EXPECT_EQ(ManagedUserService::MANUAL_NONE, managed_user_service_->GetManualBehaviorForURL(kMooseURL)); std::vector exceptions; managed_user_service_->GetManualExceptionsForHost("www.example.com", &exceptions); ASSERT_EQ(2u, exceptions.size()); EXPECT_EQ(kExampleBarURL, exceptions[0]); EXPECT_EQ(kExampleFooURL, exceptions[1]); { DictionaryPrefUpdate update(profile_->GetPrefs(), prefs::kManagedModeManualURLs); base::DictionaryValue* dict = update.Get(); for (std::vector::iterator it = exceptions.begin(); it != exceptions.end(); ++it) { dict->RemoveWithoutPathExpansion(it->spec(), NULL); } } EXPECT_EQ(ManagedUserService::MANUAL_NONE, managed_user_service_->GetManualBehaviorForURL(kExampleFooURL)); EXPECT_EQ(ManagedUserService::MANUAL_NONE, managed_user_service_->GetManualBehaviorForURL(kExampleBarURL)); EXPECT_EQ(ManagedUserService::MANUAL_ALLOW, managed_user_service_->GetManualBehaviorForURL( kExampleFooNoWWWURL)); EXPECT_EQ(ManagedUserService::MANUAL_ALLOW, managed_user_service_->GetManualBehaviorForURL(kBlurpURL)); EXPECT_EQ(ManagedUserService::MANUAL_NONE, managed_user_service_->GetManualBehaviorForURL(kMooseURL)); } // Ensure that the CustodianProfileDownloaderService shuts down cleanly. If no // DCHECK is hit when the service is destroyed, this test passed. TEST_F(ManagedUserServiceTest, ShutDownCustodianProfileDownloader) { CustodianProfileDownloaderService* downloader_service = CustodianProfileDownloaderServiceFactory::GetForProfile(profile_.get()); // Emulate being logged in, then start to download a profile so a // ProfileDownloader gets created. profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "Logged In"); downloader_service->DownloadProfile(base::Bind(&OnProfileDownloadedFail)); } #if !defined(OS_ANDROID) class ManagedUserServiceExtensionTestBase : public ExtensionServiceTestBase { public: explicit ManagedUserServiceExtensionTestBase(bool is_managed) : is_managed_(is_managed), channel_(chrome::VersionInfo::CHANNEL_DEV) {} virtual ~ManagedUserServiceExtensionTestBase() {} virtual void SetUp() OVERRIDE { ExtensionServiceTestBase::SetUp(); ExtensionServiceTestBase::ExtensionServiceInitParams params = CreateDefaultInitParams(); params.profile_is_managed = is_managed_; InitializeExtensionService(params); ManagedUserServiceFactory::GetForProfile(profile_.get())->Init(); } protected: ScopedVector GetActiveSiteLists( ManagedUserService* managed_user_service) { return managed_user_service->GetActiveSiteLists(); } scoped_refptr MakeThemeExtension() { scoped_ptr source(new base::DictionaryValue()); source->SetString(extensions::manifest_keys::kName, "Theme"); source->Set(extensions::manifest_keys::kTheme, new base::DictionaryValue()); source->SetString(extensions::manifest_keys::kVersion, "1.0"); extensions::ExtensionBuilder builder; scoped_refptr extension = builder.SetManifest(source.Pass()).Build(); return extension; } scoped_refptr MakeExtension() { scoped_ptr manifest = extensions::DictionaryBuilder() .Set(extensions::manifest_keys::kName, "Extension") .Set(extensions::manifest_keys::kVersion, "1.0") .Build(); extensions::ExtensionBuilder builder; scoped_refptr extension = builder.SetManifest(manifest.Pass()).Build(); return extension; } bool is_managed_; extensions::ScopedCurrentChannel channel_; }; class ManagedUserServiceExtensionTestUnmanaged : public ManagedUserServiceExtensionTestBase { public: ManagedUserServiceExtensionTestUnmanaged() : ManagedUserServiceExtensionTestBase(false) {} }; class ManagedUserServiceExtensionTest : public ManagedUserServiceExtensionTestBase { public: ManagedUserServiceExtensionTest() : ManagedUserServiceExtensionTestBase(true) {} }; TEST_F(ManagedUserServiceExtensionTestUnmanaged, ExtensionManagementPolicyProvider) { ManagedUserService* managed_user_service = ManagedUserServiceFactory::GetForProfile(profile_.get()); EXPECT_FALSE(profile_->IsManaged()); scoped_refptr extension = MakeExtension(); base::string16 error_1; EXPECT_TRUE(managed_user_service->UserMayLoad(extension.get(), &error_1)); EXPECT_EQ(base::string16(), error_1); base::string16 error_2; EXPECT_TRUE( managed_user_service->UserMayModifySettings(extension.get(), &error_2)); EXPECT_EQ(base::string16(), error_2); } TEST_F(ManagedUserServiceExtensionTest, ExtensionManagementPolicyProvider) { ManagedUserService* managed_user_service = ManagedUserServiceFactory::GetForProfile(profile_.get()); ManagedModeURLFilterObserver observer( managed_user_service->GetURLFilterForUIThread()); ASSERT_TRUE(profile_->IsManaged()); // Wait for the initial update to finish (otherwise we'll get leaks). observer.Wait(); // Check that a supervised user can install a theme. scoped_refptr theme = MakeThemeExtension(); base::string16 error_1; EXPECT_TRUE(managed_user_service->UserMayLoad(theme.get(), &error_1)); EXPECT_TRUE(error_1.empty()); EXPECT_TRUE( managed_user_service->UserMayModifySettings(theme.get(), &error_1)); EXPECT_TRUE(error_1.empty()); // Now check a different kind of extension. scoped_refptr extension = MakeExtension(); EXPECT_FALSE(managed_user_service->UserMayLoad(extension.get(), &error_1)); EXPECT_FALSE(error_1.empty()); base::string16 error_2; EXPECT_FALSE( managed_user_service->UserMayModifySettings(extension.get(), &error_2)); EXPECT_FALSE(error_2.empty()); #ifndef NDEBUG EXPECT_FALSE(managed_user_service->GetDebugPolicyProviderName().empty()); #endif } TEST_F(ManagedUserServiceExtensionTest, NoContentPacks) { ManagedUserService* managed_user_service = ManagedUserServiceFactory::GetForProfile(profile_.get()); ManagedModeURLFilter* url_filter = managed_user_service->GetURLFilterForUIThread(); GURL url("http://youtube.com"); ScopedVector site_lists = GetActiveSiteLists(managed_user_service); ASSERT_EQ(0u, site_lists.size()); EXPECT_EQ(ManagedModeURLFilter::ALLOW, url_filter->GetFilteringBehaviorForURL(url)); } TEST_F(ManagedUserServiceExtensionTest, InstallContentPacks) { ManagedUserService* managed_user_service = ManagedUserServiceFactory::GetForProfile(profile_.get()); ManagedModeURLFilter* url_filter = managed_user_service->GetURLFilterForUIThread(); ManagedModeURLFilterObserver observer(url_filter); observer.Wait(); GURL example_url("http://example.com"); GURL moose_url("http://moose.org"); EXPECT_EQ(ManagedModeURLFilter::ALLOW, url_filter->GetFilteringBehaviorForURL(example_url)); profile_->GetPrefs()->SetInteger(prefs::kDefaultManagedModeFilteringBehavior, ManagedModeURLFilter::BLOCK); EXPECT_EQ(ManagedModeURLFilter::BLOCK, url_filter->GetFilteringBehaviorForURL(example_url)); profile_->GetPrefs()->SetInteger(prefs::kDefaultManagedModeFilteringBehavior, ManagedModeURLFilter::WARN); EXPECT_EQ(ManagedModeURLFilter::WARN, url_filter->GetFilteringBehaviorForURL(example_url)); managed_user_service->set_elevated_for_testing(true); // Load a content pack. scoped_refptr installer( extensions::UnpackedInstaller::Create(service_)); installer->set_prompt_for_plugins(false); base::FilePath test_data_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)); base::FilePath extension_path = test_data_dir.AppendASCII("extensions/managed_mode/content_pack"); content::WindowedNotificationObserver extension_load_observer( chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, content::Source(profile_.get())); installer->Load(extension_path); extension_load_observer.Wait(); observer.Wait(); content::Details details = extension_load_observer.details(); scoped_refptr extension = make_scoped_refptr(details.ptr()); ASSERT_TRUE(extension.get()); ScopedVector site_lists = GetActiveSiteLists(managed_user_service); ASSERT_EQ(1u, site_lists.size()); std::vector sites; site_lists[0]->GetSites(&sites); ASSERT_EQ(3u, sites.size()); EXPECT_EQ(base::ASCIIToUTF16("YouTube"), sites[0].name); EXPECT_EQ(base::ASCIIToUTF16("Homestar Runner"), sites[1].name); EXPECT_EQ(base::string16(), sites[2].name); EXPECT_EQ(ManagedModeURLFilter::ALLOW, url_filter->GetFilteringBehaviorForURL(example_url)); EXPECT_EQ(ManagedModeURLFilter::WARN, url_filter->GetFilteringBehaviorForURL(moose_url)); // Load a second content pack. installer = extensions::UnpackedInstaller::Create(service_); extension_path = test_data_dir.AppendASCII("extensions/managed_mode/content_pack_2"); installer->Load(extension_path); observer.Wait(); site_lists = GetActiveSiteLists(managed_user_service); ASSERT_EQ(2u, site_lists.size()); sites.clear(); site_lists[0]->GetSites(&sites); site_lists[1]->GetSites(&sites); ASSERT_EQ(4u, sites.size()); // The site lists might be returned in any order, so we put them into a set. std::set site_names; for (std::vector::const_iterator it = sites.begin(); it != sites.end(); ++it) { site_names.insert(base::UTF16ToUTF8(it->name)); } EXPECT_TRUE(site_names.count("YouTube") == 1u); EXPECT_TRUE(site_names.count("Homestar Runner") == 1u); EXPECT_TRUE(site_names.count(std::string()) == 1u); EXPECT_TRUE(site_names.count("Moose") == 1u); EXPECT_EQ(ManagedModeURLFilter::ALLOW, url_filter->GetFilteringBehaviorForURL(example_url)); EXPECT_EQ(ManagedModeURLFilter::ALLOW, url_filter->GetFilteringBehaviorForURL(moose_url)); // Disable the first content pack. service_->DisableExtension(extension->id(), extensions::Extension::DISABLE_USER_ACTION); observer.Wait(); site_lists = GetActiveSiteLists(managed_user_service); ASSERT_EQ(1u, site_lists.size()); sites.clear(); site_lists[0]->GetSites(&sites); ASSERT_EQ(1u, sites.size()); EXPECT_EQ(base::ASCIIToUTF16("Moose"), sites[0].name); EXPECT_EQ(ManagedModeURLFilter::WARN, url_filter->GetFilteringBehaviorForURL(example_url)); EXPECT_EQ(ManagedModeURLFilter::ALLOW, url_filter->GetFilteringBehaviorForURL(moose_url)); } #endif // !defined(OS_ANDROID)