OLD | NEW |
| (Empty) |
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 """Base class for tests that need to update the policies enforced by Chrome. | |
6 | |
7 Subclasses can call SetUserPolicy (ChromeOS, Linux, Windows) and | |
8 SetDevicePolicy (ChromeOS only) with a dictionary of the policies to install. | |
9 | |
10 The current implementation depends on the platform. The implementations might | |
11 change in the future, but tests relying on the above calls will keep working. | |
12 """ | |
13 | |
14 # On ChromeOS, a mock DMServer is started and enterprise enrollment faked | |
15 # against it. The mock DMServer then serves user and device policy to Chrome. | |
16 # | |
17 # For this setup to work, the DNS, GAIA and TPM (if present) are mocked as well: | |
18 # | |
19 # * The mock DNS resolves all addresses to 127.0.0.1. This allows the mock GAIA | |
20 # to handle all login attempts. It also eliminates the impact of flaky network | |
21 # connections on tests. Beware though that no cloud services can be accessed | |
22 # due to this DNS redirect. | |
23 # | |
24 # * The mock GAIA permits login with arbitrary credentials and accepts any OAuth | |
25 # tokens sent to it for verification as valid. | |
26 # | |
27 # * When running on a real device, its TPM is disabled. If the TPM were enabled, | |
28 # enrollment could not be undone without a reboot. Disabling the TPM makes | |
29 # cryptohomed behave as if no TPM was present, allowing enrollment to be | |
30 # undone by removing the install attributes. | |
31 # | |
32 # To disable the TPM, 0 must be written to /sys/class/misc/tpm0/device/enabled. | |
33 # Since this file is not writeable, a tpmfs is mounted that shadows the file | |
34 # with a writeable copy. | |
35 | |
36 import json | |
37 import logging | |
38 import os | |
39 import subprocess | |
40 | |
41 import pyauto | |
42 | |
43 if pyauto.PyUITest.IsChromeOS(): | |
44 import sys | |
45 import warnings | |
46 | |
47 import pyauto_paths | |
48 | |
49 # Ignore deprecation warnings, they make our output more cluttered. | |
50 warnings.filterwarnings('ignore', category=DeprecationWarning) | |
51 | |
52 # Find the path to the pyproto and add it to sys.path. | |
53 # Prepend it so that google.protobuf is loaded from here. | |
54 for path in pyauto_paths.GetBuildDirs(): | |
55 p = os.path.join(path, 'pyproto') | |
56 if os.path.isdir(p): | |
57 sys.path = [p, os.path.join(p, 'chrome', 'browser', 'policy', | |
58 'proto')] + sys.path | |
59 break | |
60 sys.path.append('/usr/local') # to import autotest libs. | |
61 | |
62 import dbus | |
63 import device_management_backend_pb2 as dm | |
64 import pyauto_utils | |
65 import string | |
66 import tempfile | |
67 import urllib | |
68 import urllib2 | |
69 import uuid | |
70 from autotest.cros import auth_server | |
71 from autotest.cros import constants | |
72 from autotest.cros import cros_ui | |
73 from autotest.cros import dns_server | |
74 elif pyauto.PyUITest.IsWin(): | |
75 import _winreg as winreg | |
76 elif pyauto.PyUITest.IsMac(): | |
77 import getpass | |
78 import plistlib | |
79 | |
80 # ASN.1 object identifier for PKCS#1/RSA. | |
81 PKCS1_RSA_OID = '\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01' | |
82 | |
83 TPM_SYSFS_PATH = '/sys/class/misc/tpm0' | |
84 TPM_SYSFS_ENABLED_FILE = os.path.join(TPM_SYSFS_PATH, 'device/enabled') | |
85 | |
86 | |
87 class PolicyTestBase(pyauto.PyUITest): | |
88 """A base class for tests that need to set up and modify policies. | |
89 | |
90 Subclasses can use the methods SetUserPolicy (ChromeOS, Linux, Windows) and | |
91 SetDevicePolicy (ChromeOS only) to set the policies seen by Chrome. | |
92 """ | |
93 | |
94 if pyauto.PyUITest.IsChromeOS(): | |
95 # TODO(bartfab): Extend the C++ wrapper that starts the mock DMServer so | |
96 # that an owner can be passed in. Without this, the server will assume that | |
97 # the owner is user@example.com and for consistency, so must we. | |
98 owner = 'user@example.com' | |
99 # Subclasses may override these credentials to fake enrollment into another | |
100 # mode or use different device and machine IDs. | |
101 mode = 'enterprise' | |
102 device_id = string.upper(str(uuid.uuid4())) | |
103 machine_id = 'CROSTEST' | |
104 | |
105 _auth_server = None | |
106 _dns_server = None | |
107 | |
108 def ShouldAutoLogin(self): | |
109 return False | |
110 | |
111 @staticmethod | |
112 def _Call(command, check=False): | |
113 """Invokes a subprocess and optionally asserts the return value is zero.""" | |
114 with open(os.devnull, 'w') as devnull: | |
115 if check: | |
116 return subprocess.check_call(command.split(' '), stdout=devnull) | |
117 else: | |
118 return subprocess.call(command.split(' '), stdout=devnull) | |
119 | |
120 def _WriteFile(self, path, content): | |
121 """Writes content to path, creating any intermediary directories.""" | |
122 if not os.path.exists(os.path.dirname(path)): | |
123 os.makedirs(os.path.dirname(path)) | |
124 f = open(path, 'w') | |
125 f.write(content) | |
126 f.close() | |
127 | |
128 def _GetTestServerPoliciesFilePath(self): | |
129 """Returns the path of the cloud policy configuration file.""" | |
130 assert self.IsChromeOS() | |
131 return os.path.join(self._temp_data_dir, 'device_management') | |
132 | |
133 def _GetHttpURLForDeviceManagement(self): | |
134 """Returns the URL at which the TestServer is serving user policy.""" | |
135 assert self.IsChromeOS() | |
136 return self._http_server.GetURL('device_management').spec() | |
137 | |
138 def _RemoveIfExists(self, filename): | |
139 """Removes a file if it exists.""" | |
140 if os.path.exists(filename): | |
141 os.remove(filename) | |
142 | |
143 def _StartSessionManagerAndChrome(self): | |
144 """Starts the session manager and Chrome. | |
145 | |
146 Requires that the session manager be stopped already. | |
147 """ | |
148 # Ugly hack: session manager will not spawn Chrome if this file exists. That | |
149 # is usually a good thing (to keep the automation channel open), but in this | |
150 # case we really want to restart chrome. PyUITest.setUp() will be called | |
151 # after session manager and chrome have restarted, and will setup the | |
152 # automation channel. | |
153 restore_magic_file = False | |
154 if os.path.exists(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE): | |
155 logging.debug('DISABLE_BROWSER_RESTART_MAGIC_FILE found. ' | |
156 'Removing temporarily for the next restart.') | |
157 restore_magic_file = True | |
158 os.remove(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE) | |
159 assert not os.path.exists(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE) | |
160 | |
161 logging.debug('Starting session manager again') | |
162 cros_ui.start() | |
163 | |
164 # cros_ui.start() waits for the login prompt to be visible, so Chrome has | |
165 # already started once it returns. | |
166 if restore_magic_file: | |
167 open(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE, 'w').close() | |
168 assert os.path.exists(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE) | |
169 | |
170 def _WritePolicyOnChromeOS(self): | |
171 """Updates the mock DMServer's input file with current policy.""" | |
172 assert self.IsChromeOS() | |
173 policy_dict = { | |
174 'google/chromeos/device': self._device_policy, | |
175 'google/chromeos/user': { | |
176 'mandatory': self._user_policy, | |
177 'recommended': {}, | |
178 }, | |
179 'managed_users': ['*'], | |
180 } | |
181 self._WriteFile(self._GetTestServerPoliciesFilePath(), | |
182 json.dumps(policy_dict, sort_keys=True, indent=2) + '\n') | |
183 | |
184 @staticmethod | |
185 def _IsCryptohomedReadyOnChromeOS(): | |
186 """Checks whether cryptohomed is running and ready to accept DBus calls.""" | |
187 assert pyauto.PyUITest.IsChromeOS() | |
188 try: | |
189 bus = dbus.SystemBus() | |
190 proxy = bus.get_object('org.chromium.Cryptohome', | |
191 '/org/chromium/Cryptohome') | |
192 dbus.Interface(proxy, 'org.chromium.CryptohomeInterface') | |
193 except dbus.DBusException: | |
194 return False | |
195 return True | |
196 | |
197 def _ClearInstallAttributesOnChromeOS(self): | |
198 """Resets the install attributes.""" | |
199 assert self.IsChromeOS() | |
200 self._RemoveIfExists('/home/.shadow/install_attributes.pb') | |
201 self._Call('restart cryptohomed', check=True) | |
202 assert self.WaitUntil(self._IsCryptohomedReadyOnChromeOS) | |
203 | |
204 def _DMPostRequest(self, request_type, request, headers): | |
205 """Posts a request to the mock DMServer.""" | |
206 assert self.IsChromeOS() | |
207 url = self._GetHttpURLForDeviceManagement() | |
208 url += '?' + urllib.urlencode({ | |
209 'deviceid': self.device_id, | |
210 'oauth_token': 'dummy_oauth_token_that_is_not_checked_anyway', | |
211 'request': request_type, | |
212 'devicetype': 2, | |
213 'apptype': 'Chrome', | |
214 'agent': 'Chrome', | |
215 }) | |
216 response = dm.DeviceManagementResponse() | |
217 response.ParseFromString(urllib2.urlopen(urllib2.Request( | |
218 url, request.SerializeToString(), headers)).read()) | |
219 return response | |
220 | |
221 def _DMRegisterDevice(self): | |
222 """Registers with the mock DMServer and returns the DMToken.""" | |
223 assert self.IsChromeOS() | |
224 dm_request = dm.DeviceManagementRequest() | |
225 request = dm_request.register_request | |
226 request.type = dm.DeviceRegisterRequest.DEVICE | |
227 request.machine_id = self.machine_id | |
228 dm_response = self._DMPostRequest('register', dm_request, {}) | |
229 return dm_response.register_response.device_management_token | |
230 | |
231 def _DMFetchPolicy(self, dm_token): | |
232 """Fetches device policy from the mock DMServer.""" | |
233 assert self.IsChromeOS() | |
234 dm_request = dm.DeviceManagementRequest() | |
235 policy_request = dm_request.policy_request | |
236 request = policy_request.request.add() | |
237 request.policy_type = 'google/chromeos/device' | |
238 request.signature_type = dm.PolicyFetchRequest.SHA1_RSA | |
239 headers = {'Authorization': 'GoogleDMToken token=' + dm_token} | |
240 dm_response = self._DMPostRequest('policy', dm_request, headers) | |
241 response = dm_response.policy_response.response[0] | |
242 assert response.policy_data | |
243 assert response.policy_data_signature | |
244 assert response.new_public_key | |
245 return response | |
246 | |
247 def ExtraChromeFlags(self): | |
248 """Sets up Chrome to use cloud policies on ChromeOS.""" | |
249 flags = pyauto.PyUITest.ExtraChromeFlags(self) | |
250 if self.IsChromeOS(): | |
251 while '--skip-oauth-login' in flags: | |
252 flags.remove('--skip-oauth-login') | |
253 url = self._GetHttpURLForDeviceManagement() | |
254 flags.append('--device-management-url=' + url) | |
255 flags.append('--disable-sync') | |
256 return flags | |
257 | |
258 def _SetUpWithSessionManagerStopped(self): | |
259 """Sets up the test environment after stopping the session manager.""" | |
260 assert self.IsChromeOS() | |
261 logging.debug('Stopping session manager') | |
262 cros_ui.stop(allow_fail=True) | |
263 | |
264 # Start mock GAIA server. | |
265 self._auth_server = auth_server.GoogleAuthServer() | |
266 self._auth_server.run() | |
267 | |
268 # Disable TPM if present. | |
269 if os.path.exists(TPM_SYSFS_PATH): | |
270 self._Call('mount -t tmpfs -o size=1k tmpfs %s' | |
271 % os.path.realpath(TPM_SYSFS_PATH), check=True) | |
272 self._WriteFile(TPM_SYSFS_ENABLED_FILE, '0') | |
273 | |
274 # Clear install attributes and restart cryptohomed to pick up the change. | |
275 self._ClearInstallAttributesOnChromeOS() | |
276 | |
277 # Set install attributes to mock enterprise enrollment. | |
278 bus = dbus.SystemBus() | |
279 proxy = bus.get_object('org.chromium.Cryptohome', | |
280 '/org/chromium/Cryptohome') | |
281 install_attributes = { | |
282 'enterprise.device_id': self.device_id, | |
283 'enterprise.domain': string.split(self.owner, '@')[-1], | |
284 'enterprise.mode': self.mode, | |
285 'enterprise.owned': 'true', | |
286 'enterprise.user': self.owner | |
287 } | |
288 interface = dbus.Interface(proxy, 'org.chromium.CryptohomeInterface') | |
289 for name, value in install_attributes.iteritems(): | |
290 interface.InstallAttributesSet(name, '%s\0' % value) | |
291 interface.InstallAttributesFinalize() | |
292 | |
293 # Start mock DNS server that redirects all traffic to 127.0.0.1. | |
294 self._dns_server = dns_server.LocalDns() | |
295 self._dns_server.run() | |
296 | |
297 # Start mock DMServer. | |
298 source_dir = os.path.normpath(pyauto_paths.GetSourceDir()) | |
299 self._temp_data_dir = tempfile.mkdtemp(dir=source_dir) | |
300 logging.debug('TestServer input path: %s' % self._temp_data_dir) | |
301 relative_temp_data_dir = os.path.basename(self._temp_data_dir) | |
302 self._http_server = self.StartHTTPServer(relative_temp_data_dir) | |
303 | |
304 # Initialize the policy served. | |
305 self._device_policy = {} | |
306 self._user_policy = {} | |
307 self._WritePolicyOnChromeOS() | |
308 | |
309 # Register with mock DMServer and retrieve initial device policy blob. | |
310 dm_token = self._DMRegisterDevice() | |
311 policy = self._DMFetchPolicy(dm_token) | |
312 | |
313 # Write the initial device policy blob. | |
314 self._WriteFile(constants.OWNER_KEY_FILE, policy.new_public_key) | |
315 self._WriteFile(constants.SIGNED_POLICY_FILE, policy.SerializeToString()) | |
316 | |
317 # Remove any existing vaults. | |
318 self.RemoveAllCryptohomeVaultsOnChromeOS() | |
319 | |
320 # Restart session manager and Chrome. | |
321 self._StartSessionManagerAndChrome() | |
322 | |
323 def _tearDownWithSessionManagerStopped(self): | |
324 """Resets the test environment after stopping the session manager.""" | |
325 assert self.IsChromeOS() | |
326 logging.debug('Stopping session manager') | |
327 cros_ui.stop(allow_fail=True) | |
328 | |
329 # Stop mock GAIA server. | |
330 if self._auth_server: | |
331 self._auth_server.stop() | |
332 | |
333 # Reenable TPM if present. | |
334 if os.path.exists(TPM_SYSFS_PATH): | |
335 self._Call('umount %s' % os.path.realpath(TPM_SYSFS_PATH)) | |
336 | |
337 # Clear install attributes and restart cryptohomed to pick up the change. | |
338 self._ClearInstallAttributesOnChromeOS() | |
339 | |
340 # Stop mock DNS server. | |
341 if self._dns_server: | |
342 self._dns_server.stop() | |
343 | |
344 # Stop mock DMServer. | |
345 self.StopHTTPServer(self._http_server) | |
346 | |
347 # Clear the policy served. | |
348 pyauto_utils.RemovePath(self._temp_data_dir) | |
349 | |
350 # Remove the device policy blob. | |
351 self._RemoveIfExists(constants.OWNER_KEY_FILE) | |
352 self._RemoveIfExists(constants.SIGNED_POLICY_FILE) | |
353 | |
354 # Remove any existing vaults. | |
355 self.RemoveAllCryptohomeVaultsOnChromeOS() | |
356 | |
357 # Restart session manager and Chrome. | |
358 self._StartSessionManagerAndChrome() | |
359 | |
360 def setUp(self): | |
361 """Sets up the platform for policy testing. | |
362 | |
363 On ChromeOS, part of the setup involves restarting the session manager to | |
364 inject an initial device policy blob. | |
365 """ | |
366 if self.IsChromeOS(): | |
367 # Perform the remainder of the setup with the device manager stopped. | |
368 try: | |
369 self.WaitForSessionManagerRestart( | |
370 self._SetUpWithSessionManagerStopped) | |
371 except: | |
372 # Destroy the non re-entrant services. | |
373 if self._auth_server: | |
374 self._auth_server.stop() | |
375 if self._dns_server: | |
376 self._dns_server.stop() | |
377 raise | |
378 | |
379 pyauto.PyUITest.setUp(self) | |
380 self._branding = self.GetBrowserInfo()['properties']['branding'] | |
381 | |
382 def tearDown(self): | |
383 """Cleans up the policies and related files created in tests.""" | |
384 if self.IsChromeOS(): | |
385 # Perform the cleanup with the device manager stopped. | |
386 self.WaitForSessionManagerRestart(self._tearDownWithSessionManagerStopped) | |
387 else: | |
388 # On other platforms, there is only user policy to clear. | |
389 self.SetUserPolicy(refresh=False) | |
390 | |
391 pyauto.PyUITest.tearDown(self) | |
392 | |
393 def LoginWithTestAccount(self, account='prod_enterprise_test_user'): | |
394 """Convenience method for logging in with one of the test accounts.""" | |
395 assert self.IsChromeOS() | |
396 credentials = self.GetPrivateInfo()[account] | |
397 self.Login(credentials['username'], credentials['password']) | |
398 assert self.GetLoginInfo()['is_logged_in'] | |
399 | |
400 def _GetCurrentLoginScreenId(self): | |
401 return self.ExecuteJavascriptInOOBEWebUI( | |
402 """window.domAutomationController.send( | |
403 String(cr.ui.Oobe.getInstance().currentScreen.id)); | |
404 """) | |
405 | |
406 def _WaitForLoginScreenId(self, id): | |
407 self.assertTrue( | |
408 self.WaitUntil(function=self._GetCurrentLoginScreenId, | |
409 expect_retval=id), | |
410 msg='Expected login screen "%s" to be visible.' % id) | |
411 | |
412 def _CheckLoginFormLoading(self): | |
413 return self.ExecuteJavascriptInOOBEWebUI( | |
414 """window.domAutomationController.send( | |
415 cr.ui.Oobe.getInstance().currentScreen.loading); | |
416 """) | |
417 | |
418 def PrepareToWaitForLoginFormReload(self): | |
419 self.assertEqual('gaia-signin', | |
420 self._GetCurrentLoginScreenId(), | |
421 msg='Expected the login form to be visible.') | |
422 self.assertTrue( | |
423 self.WaitUntil(function=self._CheckLoginFormLoading, | |
424 expect_retval=False), | |
425 msg='Expected the login form to finish loading.') | |
426 # Set up a sentinel variable that is false now and will toggle to true when | |
427 # the login form starts reloading. | |
428 self.ExecuteJavascriptInOOBEWebUI( | |
429 """var screen = cr.ui.Oobe.getInstance().currentScreen; | |
430 if (!('reload_started' in screen)) { | |
431 screen.orig_loadAuthExtension_ = screen.loadAuthExtension_; | |
432 screen.loadAuthExtension_ = function(data) { | |
433 this.orig_loadAuthExtension_(data); | |
434 if (this.loading) | |
435 this.reload_started = true; | |
436 } | |
437 } | |
438 screen.reload_started = false; | |
439 window.domAutomationController.send(true);""") | |
440 | |
441 def _CheckLoginFormReloaded(self): | |
442 return self.ExecuteJavascriptInOOBEWebUI( | |
443 """window.domAutomationController.send( | |
444 cr.ui.Oobe.getInstance().currentScreen.reload_started && | |
445 !cr.ui.Oobe.getInstance().currentScreen.loading); | |
446 """) | |
447 | |
448 def WaitForLoginFormReload(self): | |
449 self.assertEqual('gaia-signin', | |
450 self._GetCurrentLoginScreenId(), | |
451 msg='Expected the login form to be visible.') | |
452 self.assertTrue( | |
453 self.WaitUntil(function=self._CheckLoginFormReloaded), | |
454 msg='Expected the login form to finish reloading.') | |
455 | |
456 def _SetUserPolicyChromeOS(self, user_policy=None): | |
457 """Writes the given user policy to the mock DMServer's input file.""" | |
458 self._user_policy = user_policy or {} | |
459 self._WritePolicyOnChromeOS() | |
460 | |
461 def _SetUserPolicyWin(self, user_policy=None): | |
462 """Writes the given user policy to the Windows registry.""" | |
463 def SetValueEx(key, sub_key, value): | |
464 if isinstance(value, int): | |
465 winreg.SetValueEx(key, sub_key, 0, winreg.REG_DWORD, int(value)) | |
466 elif isinstance(value, basestring): | |
467 winreg.SetValueEx(key, sub_key, 0, winreg.REG_SZ, value.encode('ascii')) | |
468 elif isinstance(value, list): | |
469 k = winreg.CreateKey(key, sub_key) | |
470 for index, v in list(enumerate(value)): | |
471 SetValueEx(k, str(index + 1), v) | |
472 winreg.CloseKey(k) | |
473 else: | |
474 raise TypeError('Unsupported data type: "%s"' % value) | |
475 | |
476 assert self.IsWin() | |
477 if self._branding == 'Google Chrome': | |
478 reg_base = r'SOFTWARE\Policies\Google\Chrome' | |
479 else: | |
480 reg_base = r'SOFTWARE\Policies\Chromium' | |
481 | |
482 if subprocess.call( | |
483 r'reg query HKEY_LOCAL_MACHINE\%s' % reg_base) == 0: | |
484 logging.debug(r'Removing %s' % reg_base) | |
485 subprocess.call(r'reg delete HKLM\%s /f' % reg_base) | |
486 | |
487 if user_policy is not None: | |
488 root_key = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, reg_base) | |
489 for k, v in user_policy.iteritems(): | |
490 SetValueEx(root_key, k, v) | |
491 winreg.CloseKey(root_key) | |
492 | |
493 def _SetUserPolicyLinux(self, user_policy=None): | |
494 """Writes the given user policy to the JSON policy file read by Chrome.""" | |
495 assert self.IsLinux() | |
496 sudo_cmd_file = os.path.join(os.path.dirname(__file__), | |
497 'policy_posix_util.py') | |
498 | |
499 if self._branding == 'Google Chrome': | |
500 policies_location_base = '/etc/opt/chrome' | |
501 else: | |
502 policies_location_base = '/etc/chromium' | |
503 | |
504 if os.path.exists(policies_location_base): | |
505 logging.debug('Removing directory %s' % policies_location_base) | |
506 subprocess.call(['suid-python', sudo_cmd_file, | |
507 'remove_dir', policies_location_base]) | |
508 | |
509 if user_policy is not None: | |
510 self._WriteFile('/tmp/chrome.json', | |
511 json.dumps(user_policy, sort_keys=True, indent=2) + '\n') | |
512 | |
513 policies_location = '%s/policies/managed' % policies_location_base | |
514 subprocess.call(['suid-python', sudo_cmd_file, | |
515 'setup_dir', policies_location]) | |
516 subprocess.call(['suid-python', sudo_cmd_file, | |
517 'perm_dir', policies_location]) | |
518 # Copy chrome.json file to the managed directory | |
519 subprocess.call(['suid-python', sudo_cmd_file, | |
520 'copy', '/tmp/chrome.json', policies_location]) | |
521 os.remove('/tmp/chrome.json') | |
522 | |
523 def _SetUserPolicyMac(self, user_policy=None): | |
524 """Writes the given user policy to the plist policy file read by Chrome.""" | |
525 assert self.IsMac() | |
526 sudo_cmd_file = os.path.join(os.path.dirname(__file__), | |
527 'policy_posix_util.py') | |
528 | |
529 if self._branding == 'Google Chrome': | |
530 policies_file_base = 'com.google.Chrome.plist' | |
531 else: | |
532 policies_file_base = 'org.chromium.Chromium.plist' | |
533 | |
534 policies_location = os.path.join('/Library', 'Managed Preferences', | |
535 getpass.getuser()) | |
536 | |
537 if os.path.exists(policies_location): | |
538 logging.debug('Removing directory %s' % policies_location) | |
539 subprocess.call(['suid-python', sudo_cmd_file, | |
540 'remove_dir', policies_location]) | |
541 | |
542 if user_policy is not None: | |
543 policies_tmp_file = os.path.join('/tmp', policies_file_base) | |
544 plistlib.writePlist(user_policy, policies_tmp_file) | |
545 subprocess.call(['suid-python', sudo_cmd_file, | |
546 'setup_dir', policies_location]) | |
547 # Copy policy file to the managed directory | |
548 subprocess.call(['suid-python', sudo_cmd_file, | |
549 'copy', policies_tmp_file, policies_location]) | |
550 os.remove(policies_tmp_file) | |
551 | |
552 def SetUserPolicy(self, user_policy=None, refresh=True): | |
553 """Sets the user policy provided as a dict. | |
554 | |
555 Args: | |
556 user_policy: The user policy to set. None clears it. | |
557 refresh: If True, Chrome will refresh and apply the new policy. | |
558 Requires Chrome to be alive for it. | |
559 """ | |
560 if self.IsChromeOS(): | |
561 self._SetUserPolicyChromeOS(user_policy=user_policy) | |
562 elif self.IsWin(): | |
563 self._SetUserPolicyWin(user_policy=user_policy) | |
564 elif self.IsLinux(): | |
565 self._SetUserPolicyLinux(user_policy=user_policy) | |
566 elif self.IsMac(): | |
567 self._SetUserPolicyMac(user_policy=user_policy) | |
568 else: | |
569 raise NotImplementedError('Not available on this platform.') | |
570 | |
571 if refresh: | |
572 self.RefreshPolicies() | |
573 | |
574 def SetDevicePolicy(self, device_policy=None, refresh=True): | |
575 """Sets the device policy provided as a dict. | |
576 | |
577 Args: | |
578 device_policy: The device policy to set. None clears it. | |
579 refresh: If True, Chrome will refresh and apply the new policy. | |
580 Requires Chrome to be alive for it. | |
581 """ | |
582 assert self.IsChromeOS() | |
583 self._device_policy = device_policy or {} | |
584 self._WritePolicyOnChromeOS() | |
585 if refresh: | |
586 self.RefreshPolicies() | |
OLD | NEW |