browser_credentials.py revision 3551c9c881056c480085172ff9840cab31610854
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)from telemetry.core import util
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core.chrome import facebook_credentials_backend
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core.chrome import google_credentials_backend
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)from telemetry.unittest import options_for_unittests
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BrowserCredentials(object):
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, backends = None):
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._credentials = {}
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._credentials_path = None
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._extra_credentials = {}
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if backends is None:
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backends = [
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        facebook_credentials_backend.FacebookCredentialsBackend(),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        google_credentials_backend.GoogleCredentialsBackend()]
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._backends = {}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for backend in backends:
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._backends[backend.credentials_type] = backend
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddBackend(self, backend):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert backend.credentials_type not in self._backends
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._backends[backend.credentials_type] = backend
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def IsLoggedIn(self, credentials_type):
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if credentials_type not in self._backends:
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise Exception('Unrecognized credentials type: %s', credentials_type)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if credentials_type not in self._credentials:
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return False
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._backends[credentials_type].IsLoggedIn()
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CanLogin(self, credentials_type):
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if credentials_type not in self._backends:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise Exception('Unrecognized credentials type: %s', credentials_type)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return credentials_type in self._credentials
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def LoginNeeded(self, tab, credentials_type):
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if credentials_type not in self._backends:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise Exception('Unrecognized credentials type: %s', credentials_type)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if credentials_type not in self._credentials:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._backends[credentials_type].LoginNeeded(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab, self._credentials[credentials_type])
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def LoginNoLongerNeeded(self, tab, credentials_type):
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert credentials_type in self._backends
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._backends[credentials_type].LoginNoLongerNeeded(tab)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @property
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def credentials_path(self):
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._credentials_path
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @credentials_path.setter
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def credentials_path(self, credentials_path):
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._credentials_path = credentials_path
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._RebuildCredentials()
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Add(self, credentials_type, data):
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if credentials_type not in self._extra_credentials:
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._extra_credentials[credentials_type] = {}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for k, v in data.items():
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert k not in self._extra_credentials[credentials_type]
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._extra_credentials[credentials_type][k] = v
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._RebuildCredentials()
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _ResetLoggedInState(self):
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Makes the backends think we're not logged in even though we are.
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Should only be used in unit tests to simulate --dont-override-profile.
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for backend in self._backends.keys():
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._backends[backend]._ResetLoggedInState() # pylint: disable=W0212
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _RebuildCredentials(self):
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    credentials = {}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._credentials_path == None:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pass
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif os.path.exists(self._credentials_path):
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      with open(self._credentials_path, 'r') as f:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        credentials = json.loads(f.read())
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(nduca): use system keychain, if possible.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    homedir_credentials_path = os.path.expanduser('~/.telemetry-credentials')
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    homedir_credentials = {}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (not options_for_unittests.GetCopy() and
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.path.exists(homedir_credentials_path)):
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Found ~/.telemetry-credentials. Its contents will be used "
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   "when no other credentials can be found.")
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      with open(homedir_credentials_path, 'r') as f:
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        homedir_credentials = json.loads(f.read())
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._credentials = {}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_keys = set(credentials.keys()).union(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      homedir_credentials.keys()).union(
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._extra_credentials.keys())
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for k in all_keys:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if k in credentials:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._credentials[k] = credentials[k]
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if k in homedir_credentials:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.info("Will use ~/.telemetry-credentials for %s logins." % k)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._credentials[k] = homedir_credentials[k]
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if k in self._extra_credentials:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._credentials[k] = self._extra_credentials[k]
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WarnIfMissingCredentials(self, page_set):
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_pages_missing_login = 0
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    missing_credentials = set()
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for page in page_set:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (page.credentials
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          and not self.CanLogin(page.credentials)):
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        num_pages_missing_login += 1
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        missing_credentials.add(page.credentials)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if num_pages_missing_login > 0:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      files_to_tweak = []
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if page_set.credentials_path:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        files_to_tweak.append(
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          os.path.relpath(os.path.join(os.path.dirname(page_set.file_path),
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       page_set.credentials_path)))
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      files_to_tweak.append('~/.telemetry-credentials')
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      example_credentials_file = os.path.join(
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          util.GetTelemetryDir(), 'examples', 'credentials_example.json')
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warning("""
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        Credentials for %s were not found. %i pages will not be tested.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        To fix this, either add svn-internal to your .gclient using
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        http://goto/read-src-internal, or add your own credentials to:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            %s
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        An example credentials file you can copy from is here:
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            %s\n""" % (', '.join(missing_credentials),
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         num_pages_missing_login,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         ' or '.join(files_to_tweak),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         example_credentials_file))
144