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