Home | History | Annotate | Download | only in cloud
      1 // Copyright (c) 2012 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/callback.h"
      6 #include "base/command_line.h"
      7 #include "base/file_util.h"
      8 #include "base/files/file_path.h"
      9 #include "base/files/scoped_temp_dir.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/path_service.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/run_loop.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "chrome/browser/browser_process.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/invalidation/fake_invalidation_service.h"
     18 #include "chrome/browser/invalidation/invalidation_service_factory.h"
     19 #include "chrome/browser/policy/browser_policy_connector.h"
     20 #include "chrome/browser/policy/profile_policy_connector.h"
     21 #include "chrome/browser/policy/profile_policy_connector_factory.h"
     22 #include "chrome/browser/policy/test/local_policy_test_server.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/browser/ui/browser.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/test/base/in_process_browser_test.h"
     27 #include "components/policy/core/common/cloud/cloud_policy_client.h"
     28 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
     29 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
     30 #include "components/policy/core/common/external_data_fetcher.h"
     31 #include "components/policy/core/common/policy_map.h"
     32 #include "components/policy/core/common/policy_service.h"
     33 #include "components/policy/core/common/policy_test_utils.h"
     34 #include "content/public/browser/browser_thread.h"
     35 #include "content/public/browser/notification_service.h"
     36 #include "content/public/browser/notification_source.h"
     37 #include "content/public/test/test_utils.h"
     38 #include "net/url_request/url_request_context_getter.h"
     39 #include "policy/policy_constants.h"
     40 #include "policy/proto/chrome_settings.pb.h"
     41 #include "policy/proto/cloud_policy.pb.h"
     42 #include "sync/internal_api/public/base/invalidation.h"
     43 #include "testing/gmock/include/gmock/gmock.h"
     44 #include "testing/gtest/include/gtest/gtest.h"
     45 #include "url/gurl.h"
     46 
     47 #if defined(OS_CHROMEOS)
     48 #include "chrome/browser/chromeos/login/user_manager.h"
     49 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
     50 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
     51 #include "chromeos/chromeos_paths.h"
     52 #include "chromeos/dbus/cryptohome_client.h"
     53 #else
     54 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
     55 #include "chrome/browser/signin/signin_manager.h"
     56 #include "chrome/browser/signin/signin_manager_factory.h"
     57 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
     58 #endif
     59 
     60 using testing::AnyNumber;
     61 using testing::InvokeWithoutArgs;
     62 using testing::Mock;
     63 using testing::Return;
     64 using testing::_;
     65 
     66 namespace em = enterprise_management;
     67 
     68 namespace policy {
     69 
     70 namespace {
     71 
     72 const char* GetTestUser() {
     73 #if defined(OS_CHROMEOS)
     74   return chromeos::UserManager::kStubUser;
     75 #else
     76   return "user (at) example.com";
     77 #endif
     78 }
     79 
     80 std::string GetEmptyPolicy() {
     81   const char kEmptyPolicy[] =
     82       "{"
     83       "  \"%s\": {"
     84       "    \"mandatory\": {},"
     85       "    \"recommended\": {}"
     86       "  },"
     87       "  \"managed_users\": [ \"*\" ],"
     88       "  \"policy_user\": \"%s\","
     89       "  \"current_key_index\": 0"
     90       "}";
     91 
     92   return base::StringPrintf(
     93       kEmptyPolicy, dm_protocol::kChromeUserPolicyType, GetTestUser());
     94 }
     95 
     96 std::string GetTestPolicy(const char* homepage, int key_version) {
     97   const char kTestPolicy[] =
     98       "{"
     99       "  \"%s\": {"
    100       "    \"mandatory\": {"
    101       "      \"ShowHomeButton\": true,"
    102       "      \"RestoreOnStartup\": 4,"
    103       "      \"URLBlacklist\": [ \"dev.chromium.org\", \"youtube.com\" ],"
    104       "      \"MaxInvalidationFetchDelay\": 1000"
    105       "    },"
    106       "    \"recommended\": {"
    107       "      \"HomepageLocation\": \"%s\""
    108       "    }"
    109       "  },"
    110       "  \"managed_users\": [ \"*\" ],"
    111       "  \"policy_user\": \"%s\","
    112       "  \"current_key_index\": %d,"
    113       "  \"invalidation_source\": 16,"
    114       "  \"invalidation_name\": \"test_policy\""
    115       "}";
    116 
    117   return base::StringPrintf(kTestPolicy,
    118                             dm_protocol::kChromeUserPolicyType,
    119                             homepage,
    120                             GetTestUser(),
    121                             key_version);
    122 }
    123 
    124 void GetExpectedTestPolicy(PolicyMap* expected, const char* homepage) {
    125   expected->Set(key::kShowHomeButton, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    126                 base::Value::CreateBooleanValue(true), NULL);
    127   expected->Set(key::kRestoreOnStartup, POLICY_LEVEL_MANDATORY,
    128                 POLICY_SCOPE_USER, base::Value::CreateIntegerValue(4), NULL);
    129   base::ListValue list;
    130   list.AppendString("dev.chromium.org");
    131   list.AppendString("youtube.com");
    132   expected->Set(
    133       key::kURLBlacklist, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    134       list.DeepCopy(), NULL);
    135   expected->Set(
    136       key::kMaxInvalidationFetchDelay, POLICY_LEVEL_MANDATORY,
    137       POLICY_SCOPE_USER, base::Value::CreateIntegerValue(1000), NULL);
    138   expected->Set(
    139       key::kHomepageLocation, POLICY_LEVEL_RECOMMENDED,
    140       POLICY_SCOPE_USER, base::Value::CreateStringValue(homepage), NULL);
    141 }
    142 
    143 }  // namespace
    144 
    145 // Tests the cloud policy stack(s).
    146 class CloudPolicyTest : public InProcessBrowserTest,
    147                         public PolicyService::Observer {
    148  protected:
    149   CloudPolicyTest() {}
    150   virtual ~CloudPolicyTest() {}
    151 
    152   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    153     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    154     ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetEmptyPolicy()));
    155 
    156     test_server_.reset(new LocalPolicyTestServer(policy_file_path()));
    157     ASSERT_TRUE(test_server_->Start());
    158 
    159     std::string url = test_server_->GetServiceURL().spec();
    160 
    161     CommandLine* command_line = CommandLine::ForCurrentProcess();
    162     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, url);
    163 
    164     invalidation::InvalidationServiceFactory::GetInstance()->
    165         SetBuildOnlyFakeInvalidatorsForTest(true);
    166   }
    167 
    168   virtual void SetUpOnMainThread() OVERRIDE {
    169     ASSERT_TRUE(PolicyServiceIsEmpty(g_browser_process->policy_service()))
    170         << "Pre-existing policies in this machine will make this test fail.";
    171 
    172     BrowserPolicyConnector* connector =
    173         g_browser_process->browser_policy_connector();
    174     connector->ScheduleServiceInitialization(0);
    175 
    176 #if defined(OS_CHROMEOS)
    177     UserCloudPolicyManagerChromeOS* policy_manager =
    178         UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
    179             browser()->profile());
    180     ASSERT_TRUE(policy_manager);
    181 #else
    182     // Mock a signed-in user. This is used by the UserCloudPolicyStore to pass
    183     // the username to the UserCloudPolicyValidator.
    184     SigninManager* signin_manager =
    185         SigninManagerFactory::GetForProfile(browser()->profile());
    186     ASSERT_TRUE(signin_manager);
    187     signin_manager->SetAuthenticatedUsername(GetTestUser());
    188 
    189     UserCloudPolicyManager* policy_manager =
    190         UserCloudPolicyManagerFactory::GetForBrowserContext(
    191             browser()->profile());
    192     ASSERT_TRUE(policy_manager);
    193     policy_manager->Connect(
    194         g_browser_process->local_state(),
    195         g_browser_process->system_request_context(),
    196         UserCloudPolicyManager::CreateCloudPolicyClient(
    197             connector->device_management_service(),
    198             g_browser_process->system_request_context()).Pass());
    199 #endif  // defined(OS_CHROMEOS)
    200 
    201     ASSERT_TRUE(policy_manager->core()->client());
    202     base::RunLoop run_loop;
    203     MockCloudPolicyClientObserver observer;
    204     EXPECT_CALL(observer, OnRegistrationStateChanged(_)).WillOnce(
    205         InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
    206     policy_manager->core()->client()->AddObserver(&observer);
    207 
    208     // Give a bogus OAuth token to the |policy_manager|. This should make its
    209     // CloudPolicyClient fetch the DMToken.
    210     ASSERT_FALSE(policy_manager->core()->client()->is_registered());
    211     em::DeviceRegisterRequest::Type registration_type =
    212 #if defined(OS_CHROMEOS)
    213         em::DeviceRegisterRequest::USER;
    214 #else
    215         em::DeviceRegisterRequest::BROWSER;
    216 #endif
    217     policy_manager->core()->client()->Register(
    218         registration_type, "bogus", std::string(), false, std::string());
    219     run_loop.Run();
    220     Mock::VerifyAndClearExpectations(&observer);
    221     policy_manager->core()->client()->RemoveObserver(&observer);
    222     EXPECT_TRUE(policy_manager->core()->client()->is_registered());
    223 
    224 #if defined(OS_CHROMEOS)
    225     // Get the path to the user policy key file.
    226     base::FilePath user_policy_key_dir;
    227     ASSERT_TRUE(
    228         PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &user_policy_key_dir));
    229     std::string sanitized_username =
    230         chromeos::CryptohomeClient::GetStubSanitizedUsername(GetTestUser());
    231     user_policy_key_file_ = user_policy_key_dir.AppendASCII(sanitized_username)
    232                                                .AppendASCII("policy.pub");
    233 #endif
    234   }
    235 
    236   PolicyService* GetPolicyService() {
    237     ProfilePolicyConnector* profile_connector =
    238         ProfilePolicyConnectorFactory::GetForProfile(browser()->profile());
    239     return profile_connector->policy_service();
    240   }
    241 
    242   invalidation::FakeInvalidationService* GetInvalidationService() {
    243     return static_cast<invalidation::FakeInvalidationService*>(
    244         invalidation::InvalidationServiceFactory::GetForProfile(
    245             browser()->profile()));
    246   }
    247 
    248   void SetServerPolicy(const std::string& policy) {
    249     int result = file_util::WriteFile(policy_file_path(), policy.data(),
    250                                       policy.size());
    251     ASSERT_EQ(static_cast<int>(policy.size()), result);
    252   }
    253 
    254   base::FilePath policy_file_path() const {
    255     return temp_dir_.path().AppendASCII("policy.json");
    256   }
    257 
    258   virtual void OnPolicyUpdated(const PolicyNamespace& ns,
    259                                const PolicyMap& previous,
    260                                const PolicyMap& current) OVERRIDE {
    261     if (!on_policy_updated_.is_null()) {
    262       on_policy_updated_.Run();
    263       on_policy_updated_.Reset();
    264     }
    265   }
    266 
    267   virtual void OnPolicyServiceInitialized(PolicyDomain domain) OVERRIDE {}
    268 
    269   base::ScopedTempDir temp_dir_;
    270   scoped_ptr<LocalPolicyTestServer> test_server_;
    271   base::FilePath user_policy_key_file_;
    272   base::Closure on_policy_updated_;
    273 };
    274 
    275 IN_PROC_BROWSER_TEST_F(CloudPolicyTest, FetchPolicy) {
    276   PolicyService* policy_service = GetPolicyService();
    277   {
    278     base::RunLoop run_loop;
    279     // This does the initial fetch and stores the initial key.
    280     policy_service->RefreshPolicies(run_loop.QuitClosure());
    281     run_loop.Run();
    282   }
    283 
    284   PolicyMap empty;
    285   EXPECT_TRUE(empty.Equals(policy_service->GetPolicies(
    286       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))));
    287 
    288   ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("google.com", 0)));
    289   PolicyMap expected;
    290   GetExpectedTestPolicy(&expected, "google.com");
    291   {
    292     base::RunLoop run_loop;
    293     // This fetches the new policies, using the same key.
    294     policy_service->RefreshPolicies(run_loop.QuitClosure());
    295     run_loop.Run();
    296   }
    297   EXPECT_TRUE(expected.Equals(policy_service->GetPolicies(
    298       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))));
    299 }
    300 
    301 IN_PROC_BROWSER_TEST_F(CloudPolicyTest, InvalidatePolicy) {
    302   PolicyService* policy_service = GetPolicyService();
    303   policy_service->AddObserver(POLICY_DOMAIN_CHROME, this);
    304 
    305   // Perform the initial fetch.
    306   ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("google.com", 0)));
    307   {
    308     base::RunLoop run_loop;
    309     policy_service->RefreshPolicies(run_loop.QuitClosure());
    310     run_loop.Run();
    311   }
    312 
    313   // Update the homepage in the policy and trigger an invalidation.
    314   ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("youtube.com", 0)));
    315   GetInvalidationService()->EmitInvalidationForTest(
    316       syncer::Invalidation::Init(
    317           invalidation::ObjectId(16, "test_policy"),
    318           1 /* version */,
    319           "payload"));
    320   {
    321     base::RunLoop run_loop;
    322     on_policy_updated_ = run_loop.QuitClosure();
    323     run_loop.Run();
    324   }
    325 
    326   // Check that the updated policy was fetched.
    327   PolicyMap expected;
    328   GetExpectedTestPolicy(&expected, "youtube.com");
    329   EXPECT_TRUE(expected.Equals(policy_service->GetPolicies(
    330       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))));
    331 
    332   policy_service->RemoveObserver(POLICY_DOMAIN_CHROME, this);
    333 }
    334 
    335 #if defined(OS_CHROMEOS)
    336 IN_PROC_BROWSER_TEST_F(CloudPolicyTest, FetchPolicyWithRotatedKey) {
    337   PolicyService* policy_service = GetPolicyService();
    338   {
    339     base::RunLoop run_loop;
    340     // This does the initial fetch and stores the initial key.
    341     policy_service->RefreshPolicies(run_loop.QuitClosure());
    342     run_loop.Run();
    343   }
    344 
    345   // Read the initial key.
    346   std::string initial_key;
    347   ASSERT_TRUE(base::ReadFileToString(user_policy_key_file_, &initial_key));
    348 
    349   PolicyMap empty;
    350   EXPECT_TRUE(empty.Equals(policy_service->GetPolicies(
    351       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))));
    352 
    353   // Set the new policies and a new key at the server.
    354   ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("google.com", 1)));
    355   PolicyMap expected;
    356   GetExpectedTestPolicy(&expected, "google.com");
    357   {
    358     base::RunLoop run_loop;
    359     // This fetches the new policies and does a key rotation.
    360     policy_service->RefreshPolicies(run_loop.QuitClosure());
    361     run_loop.Run();
    362   }
    363   EXPECT_TRUE(expected.Equals(policy_service->GetPolicies(
    364       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))));
    365 
    366   // Verify that the key was rotated.
    367   std::string rotated_key;
    368   ASSERT_TRUE(base::ReadFileToString(user_policy_key_file_, &rotated_key));
    369   EXPECT_NE(rotated_key, initial_key);
    370 
    371   // Another refresh using the same key won't rotate it again.
    372   {
    373     base::RunLoop run_loop;
    374     policy_service->RefreshPolicies(run_loop.QuitClosure());
    375     run_loop.Run();
    376   }
    377   EXPECT_TRUE(expected.Equals(policy_service->GetPolicies(
    378       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))));
    379   std::string current_key;
    380   ASSERT_TRUE(base::ReadFileToString(user_policy_key_file_, &current_key));
    381   EXPECT_EQ(rotated_key, current_key);
    382 }
    383 #endif
    384 
    385 TEST(CloudPolicyProtoTest, VerifyProtobufEquivalence) {
    386   // There are 2 protobufs that can be used for user cloud policy:
    387   // cloud_policy.proto and chrome_settings.proto. chrome_settings.proto is the
    388   // version used by the server, but generates one proto message per policy; to
    389   // save binary size on the client, the other version shares proto messages for
    390   // policies of the same type. They generate the same bytes on the wire though,
    391   // so they are compatible. This test verifies that that stays true.
    392 
    393   // Build a ChromeSettingsProto message with one policy of each supported type.
    394   em::ChromeSettingsProto chrome_settings;
    395   chrome_settings.mutable_homepagelocation()->set_homepagelocation(
    396       "chromium.org");
    397   chrome_settings.mutable_showhomebutton()->set_showhomebutton(true);
    398   chrome_settings.mutable_restoreonstartup()->set_restoreonstartup(4);
    399   em::StringList* list =
    400       chrome_settings.mutable_disabledschemes()->mutable_disabledschemes();
    401   list->add_entries("ftp");
    402   list->add_entries("mailto");
    403   // Try explicitly setting a policy mode too.
    404   chrome_settings.mutable_disablespdy()->set_disablespdy(false);
    405   chrome_settings.mutable_disablespdy()->mutable_policy_options()->set_mode(
    406       em::PolicyOptions::MANDATORY);
    407   chrome_settings.mutable_syncdisabled()->set_syncdisabled(true);
    408   chrome_settings.mutable_syncdisabled()->mutable_policy_options()->set_mode(
    409       em::PolicyOptions::RECOMMENDED);
    410 
    411   // Build an equivalent CloudPolicySettings message.
    412   em::CloudPolicySettings cloud_policy;
    413   cloud_policy.mutable_homepagelocation()->set_value("chromium.org");
    414   cloud_policy.mutable_showhomebutton()->set_value(true);
    415   cloud_policy.mutable_restoreonstartup()->set_value(4);
    416   list = cloud_policy.mutable_disabledschemes()->mutable_value();
    417   list->add_entries("ftp");
    418   list->add_entries("mailto");
    419   cloud_policy.mutable_disablespdy()->set_value(false);
    420   cloud_policy.mutable_disablespdy()->mutable_policy_options()->set_mode(
    421       em::PolicyOptions::MANDATORY);
    422   cloud_policy.mutable_syncdisabled()->set_value(true);
    423   cloud_policy.mutable_syncdisabled()->mutable_policy_options()->set_mode(
    424       em::PolicyOptions::RECOMMENDED);
    425 
    426   // They should now serialize to the same bytes.
    427   std::string chrome_settings_serialized;
    428   std::string cloud_policy_serialized;
    429   ASSERT_TRUE(chrome_settings.SerializeToString(&chrome_settings_serialized));
    430   ASSERT_TRUE(cloud_policy.SerializeToString(&cloud_policy_serialized));
    431   EXPECT_EQ(chrome_settings_serialized, cloud_policy_serialized);
    432 }
    433 
    434 }  // namespace policy
    435