browser_credentials.py revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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
5import logging
6import json
7import os
8
9from telemetry.core import util
10from telemetry.core.backends import facebook_credentials_backend
11from telemetry.core.backends import google_credentials_backend
12from telemetry.unittest import options_for_unittests
13
14
15class BrowserCredentials(object):
16  def __init__(self, backends = None):
17    self._credentials = {}
18    self._credentials_path = None
19    self._extra_credentials = {}
20
21    if backends is None:
22      backends = [
23        facebook_credentials_backend.FacebookCredentialsBackend(),
24        google_credentials_backend.GoogleCredentialsBackend()]
25
26    self._backends = {}
27    for backend in backends:
28      self._backends[backend.credentials_type] = backend
29
30  def AddBackend(self, backend):
31    assert backend.credentials_type not in self._backends
32    self._backends[backend.credentials_type] = backend
33
34  def IsLoggedIn(self, credentials_type):
35    if credentials_type not in self._backends:
36      raise Exception('Unrecognized credentials type: %s', credentials_type)
37    if credentials_type not in self._credentials:
38      return False
39    return self._backends[credentials_type].IsLoggedIn()
40
41  def CanLogin(self, credentials_type):
42    if credentials_type not in self._backends:
43      raise Exception('Unrecognized credentials type: %s', credentials_type)
44    return credentials_type in self._credentials
45
46  def LoginNeeded(self, tab, credentials_type):
47    if credentials_type not in self._backends:
48      raise Exception('Unrecognized credentials type: %s', credentials_type)
49    if credentials_type not in self._credentials:
50      return False
51    return self._backends[credentials_type].LoginNeeded(
52      tab, self._credentials[credentials_type])
53
54  def LoginNoLongerNeeded(self, tab, credentials_type):
55    assert credentials_type in self._backends
56    self._backends[credentials_type].LoginNoLongerNeeded(tab)
57
58  @property
59  def credentials_path(self):
60    return self._credentials_path
61
62  @credentials_path.setter
63  def credentials_path(self, credentials_path):
64    self._credentials_path = credentials_path
65    self._RebuildCredentials()
66
67  def Add(self, credentials_type, data):
68    if credentials_type not in self._extra_credentials:
69      self._extra_credentials[credentials_type] = {}
70    for k, v in data.items():
71      assert k not in self._extra_credentials[credentials_type]
72      self._extra_credentials[credentials_type][k] = v
73    self._RebuildCredentials()
74
75  def _ResetLoggedInState(self):
76    """Makes the backends think we're not logged in even though we are.
77    Should only be used in unit tests to simulate --dont-override-profile.
78    """
79    for backend in self._backends.keys():
80      self._backends[backend]._ResetLoggedInState() # pylint: disable=W0212
81
82  def _RebuildCredentials(self):
83    credentials = {}
84    if self._credentials_path == None:
85      pass
86    elif os.path.exists(self._credentials_path):
87      with open(self._credentials_path, 'r') as f:
88        credentials = json.loads(f.read())
89
90    # TODO(nduca): use system keychain, if possible.
91    homedir_credentials_path = os.path.expanduser('~/.telemetry-credentials')
92    homedir_credentials = {}
93
94    if (not options_for_unittests.GetCopy() and
95        os.path.exists(homedir_credentials_path)):
96      logging.info("Found ~/.telemetry-credentials. Its contents will be used "
97                   "when no other credentials can be found.")
98      with open(homedir_credentials_path, 'r') as f:
99        homedir_credentials = json.loads(f.read())
100
101    self._credentials = {}
102    all_keys = set(credentials.keys()).union(
103      homedir_credentials.keys()).union(
104      self._extra_credentials.keys())
105
106    for k in all_keys:
107      if k in credentials:
108        self._credentials[k] = credentials[k]
109      if k in homedir_credentials:
110        logging.info("Will use ~/.telemetry-credentials for %s logins." % k)
111        self._credentials[k] = homedir_credentials[k]
112      if k in self._extra_credentials:
113        self._credentials[k] = self._extra_credentials[k]
114
115  def WarnIfMissingCredentials(self, page_set):
116    num_pages_missing_login = 0
117    missing_credentials = set()
118    for page in page_set:
119      if (page.credentials
120          and not self.CanLogin(page.credentials)):
121        num_pages_missing_login += 1
122        missing_credentials.add(page.credentials)
123
124    if num_pages_missing_login > 0:
125      files_to_tweak = []
126      if page_set.credentials_path:
127        files_to_tweak.append(
128          os.path.relpath(os.path.join(os.path.dirname(page_set.file_path),
129                                       page_set.credentials_path)))
130      files_to_tweak.append('~/.telemetry-credentials')
131
132      example_credentials_file = os.path.join(
133          util.GetTelemetryDir(), 'examples', 'credentials_example.json')
134
135      logging.warning("""
136        Credentials for %s were not found. %i pages will not be tested.
137
138        To fix this, either add svn-internal to your .gclient using
139        http://goto/read-src-internal, or add your own credentials to:
140            %s
141        An example credentials file you can copy from is here:
142            %s\n""" % (', '.join(missing_credentials),
143         num_pages_missing_login,
144         ' or '.join(files_to_tweak),
145         example_credentials_file))
146