| 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 | 
|---|