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