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
48using testing::InvokeWithoutArgs;
49using testing::Mock;
50using testing::Return;
51using testing::_;
52
53namespace em = enterprise_management;
54
55namespace policy {
56
57namespace {
58
59const char kDMToken[] = "dmtoken";
60const char kDeviceID[] = "deviceid";
61
62const char kTestExtension[] = "kjmkgkdkpedkejedfhmfcenooemhbpbo";
63
64const base::FilePath::CharType kTestExtensionPath[] =
65    FILE_PATH_LITERAL("extensions/managed_extension");
66
67const char kTestPolicy[] =
68    "{"
69    "  \"Name\": {"
70    "    \"Value\": \"disable_all_the_things\""
71    "  }"
72    "}";
73
74const char kTestExtension2[] = "behllobkkfkfnphdnhnkndlbkcpglgmj";
75const base::FilePath::CharType kTestExtension2Path[] =
76    FILE_PATH_LITERAL("extensions/managed_extension2");
77
78const char kTestPolicyJSON[] = "{\"Name\":\"disable_all_the_things\"}";
79
80const char kTestPolicy2[] =
81    "{"
82    "  \"Another\": {"
83    "    \"Value\": \"turn_it_off\""
84    "  }"
85    "}";
86
87const char kTestPolicy2JSON[] = "{\"Another\":\"turn_it_off\"}";
88
89#if !defined(OS_CHROMEOS)
90// Same encoding as ResourceCache does for its keys.
91bool 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
103class 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@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@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
235IN_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
242IN_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
269IN_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)
299IN_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