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