Home | History | Annotate | Download | only in cloud
      1 // Copyright (c) 2013 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 <string>
      6 
      7 #include "base/base64.h"
      8 #include "base/command_line.h"
      9 #include "base/files/file_path.h"
     10 #include "base/files/file_util.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/path_service.h"
     13 #include "base/run_loop.h"
     14 #include "base/strings/string_util.h"
     15 #include "chrome/browser/browser_process.h"
     16 #include "chrome/browser/extensions/extension_browsertest.h"
     17 #include "chrome/browser/policy/profile_policy_connector.h"
     18 #include "chrome/browser/policy/profile_policy_connector_factory.h"
     19 #include "chrome/browser/policy/test/local_policy_test_server.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/ui/browser.h"
     22 #include "chrome/common/chrome_paths.h"
     23 #include "components/policy/core/browser/browser_policy_connector.h"
     24 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
     25 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
     26 #include "components/policy/core/common/policy_service.h"
     27 #include "components/policy/core/common/policy_switches.h"
     28 #include "components/policy/core/common/policy_test_utils.h"
     29 #include "extensions/common/extension.h"
     30 #include "extensions/test/extension_test_message_listener.h"
     31 #include "net/url_request/url_request_context_getter.h"
     32 #include "policy/proto/chrome_extension_policy.pb.h"
     33 #include "policy/proto/cloud_policy.pb.h"
     34 #include "testing/gmock/include/gmock/gmock.h"
     35 #include "testing/gtest/include/gtest/gtest.h"
     36 
     37 #if defined(OS_CHROMEOS)
     38 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
     39 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
     40 #include "chromeos/chromeos_switches.h"
     41 #else
     42 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
     43 #include "chrome/browser/signin/signin_manager_factory.h"
     44 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
     45 #include "components/signin/core/browser/signin_manager.h"
     46 #endif
     47 
     48 using testing::InvokeWithoutArgs;
     49 using testing::Mock;
     50 using testing::Return;
     51 using testing::_;
     52 
     53 namespace em = enterprise_management;
     54 
     55 namespace policy {
     56 
     57 namespace {
     58 
     59 const char kDMToken[] = "dmtoken";
     60 const char kDeviceID[] = "deviceid";
     61 
     62 const char kTestExtension[] = "kjmkgkdkpedkejedfhmfcenooemhbpbo";
     63 
     64 const base::FilePath::CharType kTestExtensionPath[] =
     65     FILE_PATH_LITERAL("extensions/managed_extension");
     66 
     67 const char kTestPolicy[] =
     68     "{"
     69     "  \"Name\": {"
     70     "    \"Value\": \"disable_all_the_things\""
     71     "  }"
     72     "}";
     73 
     74 const char kTestExtension2[] = "behllobkkfkfnphdnhnkndlbkcpglgmj";
     75 const base::FilePath::CharType kTestExtension2Path[] =
     76     FILE_PATH_LITERAL("extensions/managed_extension2");
     77 
     78 const char kTestPolicyJSON[] = "{\"Name\":\"disable_all_the_things\"}";
     79 
     80 const char kTestPolicy2[] =
     81     "{"
     82     "  \"Another\": {"
     83     "    \"Value\": \"turn_it_off\""
     84     "  }"
     85     "}";
     86 
     87 const char kTestPolicy2JSON[] = "{\"Another\":\"turn_it_off\"}";
     88 
     89 #if !defined(OS_CHROMEOS)
     90 // Same encoding as ResourceCache does for its keys.
     91 bool Base64UrlEncode(const std::string& value, std::string* encoded) {
     92   if (value.empty())
     93     return false;
     94   base::Base64Encode(value, encoded);
     95   base::ReplaceChars(*encoded, "+", "-", encoded);
     96   base::ReplaceChars(*encoded, "/", "_", encoded);
     97   return true;
     98 }
     99 #endif
    100 
    101 }  // namespace
    102 
    103 class ComponentCloudPolicyTest : public ExtensionBrowserTest {
    104  protected:
    105   ComponentCloudPolicyTest() {}
    106   virtual ~ComponentCloudPolicyTest() {}
    107 
    108   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    109     ExtensionBrowserTest::SetUpCommandLine(command_line);
    110 #if defined(OS_CHROMEOS)
    111     // ExtensionBrowserTest sets the login users to a non-managed value;
    112     // replace it. This is the default username sent in policy blobs from the
    113     // testserver.
    114     command_line->AppendSwitchASCII(
    115         ::chromeos::switches::kLoginUser, "user (at) example.com");
    116 #endif
    117   }
    118 
    119   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    120     test_server_.RegisterClient(kDMToken, kDeviceID);
    121     EXPECT_TRUE(test_server_.UpdatePolicyData(
    122         dm_protocol::kChromeExtensionPolicyType, kTestExtension, kTestPolicy));
    123     ASSERT_TRUE(test_server_.Start());
    124 
    125     std::string url = test_server_.GetServiceURL().spec();
    126     CommandLine* command_line = CommandLine::ForCurrentProcess();
    127     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, url);
    128 
    129     ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
    130   }
    131 
    132   virtual void SetUpOnMainThread() OVERRIDE {
    133     ASSERT_TRUE(PolicyServiceIsEmpty(g_browser_process->policy_service()))
    134         << "Pre-existing policies in this machine will make this test fail.";
    135 
    136     // Install the initial extension.
    137     ExtensionTestMessageListener ready_listener("ready", true);
    138     event_listener_.reset(new ExtensionTestMessageListener("event", true));
    139     extension_ = LoadExtension(kTestExtensionPath);
    140     ASSERT_TRUE(extension_.get());
    141     ASSERT_EQ(kTestExtension, extension_->id());
    142     EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
    143 
    144     // And start with a signed-in user.
    145     SignInAndRegister();
    146 
    147     // The extension will receive an update event.
    148     EXPECT_TRUE(event_listener_->WaitUntilSatisfied());
    149 
    150     ExtensionBrowserTest::SetUpOnMainThread();
    151   }
    152 
    153   scoped_refptr<const extensions::Extension> LoadExtension(
    154       const base::FilePath::CharType* path) {
    155     base::FilePath full_path;
    156     if (!PathService::Get(chrome::DIR_TEST_DATA, &full_path)) {
    157       ADD_FAILURE();
    158       return NULL;
    159     }
    160     scoped_refptr<const extensions::Extension> extension(
    161         ExtensionBrowserTest::LoadExtension(full_path.Append(path)));
    162     if (!extension.get()) {
    163       ADD_FAILURE();
    164       return NULL;
    165     }
    166     return extension;
    167   }
    168 
    169   void SignInAndRegister() {
    170     BrowserPolicyConnector* connector =
    171         g_browser_process->browser_policy_connector();
    172     connector->ScheduleServiceInitialization(0);
    173 
    174 #if defined(OS_CHROMEOS)
    175     UserCloudPolicyManagerChromeOS* policy_manager =
    176         UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
    177             browser()->profile());
    178     ASSERT_TRUE(policy_manager);
    179 #else
    180     // Mock a signed-in user. This is used by the UserCloudPolicyStore to pass
    181     // the username to the UserCloudPolicyValidator.
    182     SigninManager* signin_manager =
    183         SigninManagerFactory::GetForProfile(browser()->profile());
    184     ASSERT_TRUE(signin_manager);
    185     signin_manager->SetAuthenticatedUsername("user (at) example.com");
    186 
    187     UserCloudPolicyManager* policy_manager =
    188         UserCloudPolicyManagerFactory::GetForBrowserContext(
    189             browser()->profile());
    190     ASSERT_TRUE(policy_manager);
    191     policy_manager->Connect(
    192         g_browser_process->local_state(),
    193         g_browser_process->system_request_context(),
    194         UserCloudPolicyManager::CreateCloudPolicyClient(
    195             connector->device_management_service(),
    196             g_browser_process->system_request_context()).Pass());
    197 #endif  // defined(OS_CHROMEOS)
    198 
    199     // Register the cloud policy client.
    200     ASSERT_TRUE(policy_manager->core()->client());
    201     base::RunLoop run_loop;
    202     MockCloudPolicyClientObserver observer;
    203     EXPECT_CALL(observer, OnRegistrationStateChanged(_))
    204         .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
    205     policy_manager->core()->client()->AddObserver(&observer);
    206     policy_manager->core()->client()->SetupRegistration(kDMToken, kDeviceID);
    207     run_loop.Run();
    208     Mock::VerifyAndClearExpectations(&observer);
    209     policy_manager->core()->client()->RemoveObserver(&observer);
    210   }
    211 
    212 #if !defined(OS_CHROMEOS)
    213   void SignOut() {
    214     SigninManager* signin_manager =
    215         SigninManagerFactory::GetForProfile(browser()->profile());
    216     ASSERT_TRUE(signin_manager);
    217     signin_manager->SignOut(signin_metrics::SIGNOUT_TEST);
    218   }
    219 #endif
    220 
    221   void RefreshPolicies() {
    222     ProfilePolicyConnector* profile_connector =
    223         ProfilePolicyConnectorFactory::GetForProfile(browser()->profile());
    224     PolicyService* policy_service = profile_connector->policy_service();
    225     base::RunLoop run_loop;
    226     policy_service->RefreshPolicies(run_loop.QuitClosure());
    227     run_loop.Run();
    228   }
    229 
    230   LocalPolicyTestServer test_server_;
    231   scoped_refptr<const extensions::Extension> extension_;
    232   scoped_ptr<ExtensionTestMessageListener> event_listener_;
    233 };
    234 
    235 IN_PROC_BROWSER_TEST_F(ComponentCloudPolicyTest, FetchExtensionPolicy) {
    236   // Read the initial policy.
    237   ExtensionTestMessageListener policy_listener(kTestPolicyJSON, true);
    238   event_listener_->Reply("get-policy-Name");
    239   EXPECT_TRUE(policy_listener.WaitUntilSatisfied());
    240 }
    241 
    242 IN_PROC_BROWSER_TEST_F(ComponentCloudPolicyTest, UpdateExtensionPolicy) {
    243   // Read the initial policy.
    244   ExtensionTestMessageListener policy_listener(kTestPolicyJSON, true);
    245   event_listener_->Reply("get-policy-Name");
    246   EXPECT_TRUE(policy_listener.WaitUntilSatisfied());
    247 
    248   // Update the policy at the server and reload policy.
    249   event_listener_.reset(new ExtensionTestMessageListener("event", true));
    250   policy_listener.Reply("idle");
    251   EXPECT_TRUE(test_server_.UpdatePolicyData(
    252       dm_protocol::kChromeExtensionPolicyType, kTestExtension, kTestPolicy2));
    253   RefreshPolicies();
    254 
    255   // Check that the update event was received, and verify the new policy
    256   // values.
    257   EXPECT_TRUE(event_listener_->WaitUntilSatisfied());
    258 
    259   // This policy was removed.
    260   ExtensionTestMessageListener policy_listener1("{}", true);
    261   event_listener_->Reply("get-policy-Name");
    262   EXPECT_TRUE(policy_listener1.WaitUntilSatisfied());
    263 
    264   ExtensionTestMessageListener policy_listener2(kTestPolicy2JSON, true);
    265   policy_listener1.Reply("get-policy-Another");
    266   EXPECT_TRUE(policy_listener2.WaitUntilSatisfied());
    267 }
    268 
    269 IN_PROC_BROWSER_TEST_F(ComponentCloudPolicyTest, InstallNewExtension) {
    270   EXPECT_TRUE(test_server_.UpdatePolicyData(
    271       dm_protocol::kChromeExtensionPolicyType, kTestExtension2, kTestPolicy2));
    272   // Installing a new extension doesn't trigger another policy fetch because
    273   // the server always sends down the list of all extensions that have policy.
    274   // Fetch now that the configuration has been updated and before installing
    275   // the extension.
    276   RefreshPolicies();
    277 
    278   ExtensionTestMessageListener result_listener("ok", true);
    279   result_listener.set_failure_message("fail");
    280   scoped_refptr<const extensions::Extension> extension2 =
    281       LoadExtension(kTestExtension2Path);
    282   ASSERT_TRUE(extension2.get());
    283   ASSERT_EQ(kTestExtension2, extension2->id());
    284 
    285   // This extension only sends the 'policy' signal once it receives the policy,
    286   // and after verifying it has the expected value. Otherwise it sends 'fail'.
    287   EXPECT_TRUE(result_listener.WaitUntilSatisfied());
    288 }
    289 
    290 // Signing out on Chrome OS is a different process from signing out on the
    291 // Desktop platforms. On Chrome OS the session is ended, and the user goes back
    292 // to the sign-in screen; the Profile data is not affected. On the Desktop the
    293 // session goes on though, and all the signed-in services are disconnected;
    294 // in particular, the policy caches are dropped if the user signs out.
    295 // This test verifies that when the user signs out then any existing component
    296 // policy caches are dropped, and that it's still possible to sign back in and
    297 // get policy for components working again.
    298 #if !defined(OS_CHROMEOS)
    299 IN_PROC_BROWSER_TEST_F(ComponentCloudPolicyTest, SignOutAndBackIn) {
    300   // Read the initial policy.
    301   ExtensionTestMessageListener initial_policy_listener(kTestPolicyJSON, true);
    302   event_listener_->Reply("get-policy-Name");
    303   EXPECT_TRUE(initial_policy_listener.WaitUntilSatisfied());
    304 
    305   // Verify that the policy cache exists.
    306   std::string cache_key;
    307   ASSERT_TRUE(Base64UrlEncode("extension-policy", &cache_key));
    308   std::string cache_subkey;
    309   ASSERT_TRUE(Base64UrlEncode(kTestExtension, &cache_subkey));
    310   base::FilePath cache_path = browser()->profile()->GetPath()
    311       .Append(FILE_PATH_LITERAL("Policy"))
    312       .Append(FILE_PATH_LITERAL("Components"))
    313       .AppendASCII(cache_key)
    314       .AppendASCII(cache_subkey);
    315   EXPECT_TRUE(base::PathExists(cache_path));
    316 
    317   // Now sign-out. The policy cache should be removed, and the extension should
    318   // get an empty policy update.
    319   ExtensionTestMessageListener event_listener("event", true);
    320   initial_policy_listener.Reply("idle");
    321   SignOut();
    322   EXPECT_TRUE(event_listener.WaitUntilSatisfied());
    323 
    324   // The extension got an update event; verify that the policy was empty.
    325   ExtensionTestMessageListener signout_policy_listener("{}", true);
    326   event_listener.Reply("get-policy-Name");
    327   EXPECT_TRUE(signout_policy_listener.WaitUntilSatisfied());
    328 
    329   // Verify that the cache is gone.
    330   EXPECT_FALSE(base::PathExists(cache_path));
    331 
    332   // Verify that the policy is fetched again if the user signs back in.
    333   ExtensionTestMessageListener event_listener2("event", true);
    334   SignInAndRegister();
    335   EXPECT_TRUE(event_listener2.WaitUntilSatisfied());
    336 
    337   // The extension got updated policy; verify it.
    338   ExtensionTestMessageListener signin_policy_listener(kTestPolicyJSON, true);
    339   event_listener2.Reply("get-policy-Name");
    340   EXPECT_TRUE(signin_policy_listener.WaitUntilSatisfied());
    341 
    342   // And the cache is back.
    343   EXPECT_TRUE(base::PathExists(cache_path));
    344 }
    345 #endif
    346 
    347 }  // namespace policy
    348