Support for Remora enrollment.
* Methods for enterprise enrollment of Remora devices.
* Methods to save TPM password and clear TPM.
* utility function to read credentials from a file.
* sample test that exercises enrollment.
BUG=chromium:342884
TEST=enterprise_RemoraRequisition
Change-Id: Ie872e9ba0702474d9f605c5520577cf4e0ad21d2
Reviewed-on: https://chromium-review.googlesource.com/199560
Tested-by: Achuith Bhandarkar <achuith@chromium.org>
Commit-Queue: Mattias Nissler <mnissler@chromium.org>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
Commit-Queue: Achuith Bhandarkar <achuith@chromium.org>
diff --git a/client/bin/site_utils.py b/client/bin/site_utils.py
index 33beabd..26ac5fe 100644
--- a/client/bin/site_utils.py
+++ b/client/bin/site_utils.py
@@ -349,6 +349,21 @@
return str(uuid.uuid4()) + '@example.com'
+def get_signin_credentials(filepath):
+ """Returns user_id, password tuple from credentials file at filepath.
+
+ File must have one line of the format user_id:password
+
+ @param filepath: path of credentials file.
+ @return user_id, password tuple.
+ """
+ user_id, password = None, None
+ if os.path.isfile(filepath):
+ with open(filepath) as f:
+ user_id, password = f.read().rstrip().split(':')
+ return user_id, password
+
+
def parse_cmd_output(command, run_method=utils.run):
"""Runs a command on a host object to retrieve host attributes.
diff --git a/client/common_lib/cros/enrollment.py b/client/common_lib/cros/enrollment.py
new file mode 100644
index 0000000..f4c8a35
--- /dev/null
+++ b/client/common_lib/cros/enrollment.py
@@ -0,0 +1,119 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging, os
+
+from autotest_lib.client.bin import utils
+from autotest_lib.client.cros import cros_ui, cryptohome, ownership
+from telemetry.core import exceptions
+from telemetry.core.backends.chrome import cros_interface
+
+
+_PASSWD_FILE = '/var/tmp/tpm_passwd'
+
+
+def ClearTPM():
+ """Clears the TPM (if it is owned) using the password stored in
+ /var/tmp/tpm_passwd. Returns True if tpm was owned.
+
+ @return True if the TPM was owned - enrollment should not be attempted.
+ """
+ status = cryptohome.get_tpm_status()
+ if not status['Owned']:
+ logging.debug('TPM is not owned')
+ return False
+ password = status['Password']
+ if not password:
+ if not os.path.isfile(_PASSWD_FILE):
+ logging.warn('Password file %s doesn\'t exist, cannot clear TPM. '
+ 'You need to have the firmware clear the TPM, for '
+ 'instance using crossystem or by toggling the dev '
+ 'switch.', _PASSWD_FILE)
+ return True
+ with open(_PASSWD_FILE) as f:
+ password = f.read().rstrip()
+
+ if not password:
+ logging.warn('Password file %s empty, cannot clear TPM. '
+ 'You need to have the firmware clear the TPM, for '
+ 'instance using crossystem or by toggling the dev switch.',
+ _PASSWD_FILE)
+ return True
+
+ cros_ui.stop()
+ res = utils.system_output('tpm_clear --pass ' + password)
+ logging.warn(repr(res))
+
+ cryptohome.remove_all_vaults()
+ ownership.clear_ownership_files_no_restart()
+ logging.warn('Please reboot the system')
+ return True
+
+
+def _SaveTPMPassword():
+ """Save TPM Password to /var/tpm/tpm_passwd.
+
+ During enrollment, the TPM password becomes visible - we capture it and
+ save it in to a local file, so we can clear the TPM at the end of the test.
+ """
+ password = utils.poll_for_condition(
+ lambda: cryptohome.get_tpm_status()['Password'],
+ sleep_interval=0.5, timeout=60)
+ if password:
+ with open(_PASSWD_FILE, 'w') as f:
+ f.write(password)
+ else:
+ logging.warn('Could not save TPM password')
+ logging.info('TPM Password: ' + password)
+ return password
+
+
+def _ExecuteOobeCmd(browser, cmd):
+ logging.info('Invoking ' + cmd)
+ oobe = browser.oobe
+ oobe.WaitForJavaScriptExpression('typeof Oobe !== \'undefined\'', 10)
+ oobe.ExecuteJavaScript(cmd)
+
+
+def SwitchToRemora(browser):
+ """Switch to Remora enrollment.
+
+ @param browser: telemetry browser object.
+ """
+ _cri = cros_interface.CrOSInterface()
+ pid = _cri.GetChromePid()
+ try:
+ # This will restart the browser.
+ _ExecuteOobeCmd(browser, 'Oobe.remoraRequisitionForTesting();')
+ except (exceptions.BrowserConnectionGoneException,
+ exceptions.TabCrashException):
+ pass
+ utils.poll_for_condition(lambda: pid != _cri.GetChromePid(), timeout=60)
+ utils.poll_for_condition(lambda: browser.oobe_exists, timeout=30)
+
+ _ExecuteOobeCmd(browser, 'Oobe.skipToLoginForTesting();')
+ _SaveTPMPassword()
+
+
+def FinishEnrollment(oobe):
+ """Wait for enrollment to finish and dismiss the last enrollment screen.
+
+ @param oobe: telemetry oobe object.
+ """
+ oobe.WaitForJavaScriptExpression(
+ "document.getElementById('oauth-enrollment').className."
+ "search('oauth-enroll-state-success') != -1", 30)
+ oobe.EvaluateJavaScript('Oobe.enterpriseEnrollmentDone();')
+
+
+def RemoraEnrollment(browser, user_id, password):
+ """Enterprise login for a Remora device.
+
+ @param browser: telemetry browser object.
+ @param user_id: login credentials user_id.
+ @param password: login credentials password.
+ """
+ SwitchToRemora(browser)
+ browser.oobe.NavigateGaiaLogin(user_id, password)
+ FinishEnrollment(browser.oobe)
diff --git a/client/site_tests/enterprise_RemoraRequisition/control b/client/site_tests/enterprise_RemoraRequisition/control
new file mode 100644
index 0000000..d40df8f
--- /dev/null
+++ b/client/site_tests/enterprise_RemoraRequisition/control
@@ -0,0 +1,20 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = "achuith"
+NAME = "enterprise_RemoraRequisition"
+TIME = "SHORT"
+TEST_CATEGORY = "Enterprise"
+TEST_CLASS = "enterprise"
+TEST_TYPE = "client"
+
+DOC = """
+This test enrolls a Chrome device as a Remora device.
+
+You need a credentials.txt file with user_id:password in this directory for
+this test to succeed. The credentials are used to enroll the device as a Remora
+device.
+"""
+
+job.run_test('enterprise_RemoraRequisition')
diff --git a/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py b/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py
new file mode 100644
index 0000000..ac5adf0
--- /dev/null
+++ b/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py
@@ -0,0 +1,29 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging, os
+
+from autotest_lib.client.bin import test, utils
+from autotest_lib.client.common_lib.cros import chrome, enrollment
+
+
+class enterprise_RemoraRequisition(test.test):
+ """Enroll as a Remora device."""
+ version = 1
+
+ def run_once(self):
+ if enrollment.ClearTPM():
+ return
+
+ user_id, password = utils.get_signin_credentials(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'credentials.txt'))
+ if user_id and password:
+ with chrome.Chrome(auto_login=False) as cr:
+ enrollment.RemoraEnrollment(cr.browser, user_id, password)
+ # TODO(achuith): Additional logic to ensure the hangouts app is
+ # functioning correctly.
+
+ enrollment.ClearTPM()
+ else:
+ logging.warn('No credentials found - exiting test.')