OLD | NEW |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Google OAuth2 related functions.""" | 5 """Google OAuth2 related functions.""" |
6 | 6 |
7 import BaseHTTPServer | 7 import BaseHTTPServer |
8 import collections | 8 import collections |
9 import datetime | 9 import datetime |
10 import functools | 10 import functools |
(...skipping 30 matching lines...) Expand all Loading... |
41 # anyway. | 41 # anyway. |
42 # This particular set is managed by API Console project "chrome-infra-auth". | 42 # This particular set is managed by API Console project "chrome-infra-auth". |
43 OAUTH_CLIENT_ID = ( | 43 OAUTH_CLIENT_ID = ( |
44 '446450136466-2hr92jrq8e6i4tnsa56b52vacp7t3936.apps.googleusercontent.com') | 44 '446450136466-2hr92jrq8e6i4tnsa56b52vacp7t3936.apps.googleusercontent.com') |
45 OAUTH_CLIENT_SECRET = 'uBfbay2KCy9t4QveJ-dOqHtp' | 45 OAUTH_CLIENT_SECRET = 'uBfbay2KCy9t4QveJ-dOqHtp' |
46 | 46 |
47 # List of space separated OAuth scopes for generated tokens. GAE apps usually | 47 # List of space separated OAuth scopes for generated tokens. GAE apps usually |
48 # use userinfo.email scope for authentication. | 48 # use userinfo.email scope for authentication. |
49 OAUTH_SCOPES = 'https://www.googleapis.com/auth/userinfo.email' | 49 OAUTH_SCOPES = 'https://www.googleapis.com/auth/userinfo.email' |
50 | 50 |
51 # Path to a file with cached OAuth2 credentials used by default. It should be | 51 # Path to a file with cached OAuth2 credentials used by default relative to the |
52 # a safe location accessible only to a current user: knowing content of this | 52 # home dir (see _get_token_cache_path). It should be a safe location accessible |
53 # file is roughly equivalent to knowing account password. Single file can hold | 53 # only to a current user: knowing content of this file is roughly equivalent to |
54 # multiple independent tokens identified by token_cache_key (see Authenticator). | 54 # knowing account password. Single file can hold multiple independent tokens |
55 OAUTH_TOKENS_CACHE = os.path.join( | 55 # identified by token_cache_key (see Authenticator). |
56 os.path.expanduser('~'), '.depot_tools_oauth2_tokens') | 56 OAUTH_TOKENS_CACHE = '.depot_tools_oauth2_tokens' |
57 | 57 |
58 | 58 |
59 # Authentication configuration extracted from command line options. | 59 # Authentication configuration extracted from command line options. |
60 # See doc string for 'make_auth_config' for meaning of fields. | 60 # See doc string for 'make_auth_config' for meaning of fields. |
61 AuthConfig = collections.namedtuple('AuthConfig', [ | 61 AuthConfig = collections.namedtuple('AuthConfig', [ |
62 'use_oauth2', # deprecated, will be always True | 62 'use_oauth2', # deprecated, will be always True |
63 'save_cookies', # deprecated, will be removed | 63 'save_cookies', # deprecated, will be removed |
64 'use_local_webserver', | 64 'use_local_webserver', |
65 'webserver_port', | 65 'webserver_port', |
66 'refresh_token_json', | 66 'refresh_token_json', |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 ## Private methods. | 376 ## Private methods. |
377 | 377 |
378 def _get_storage(self): | 378 def _get_storage(self): |
379 """Returns oauth2client.Storage with cached tokens.""" | 379 """Returns oauth2client.Storage with cached tokens.""" |
380 # Do not mix cache keys for different externally provided tokens. | 380 # Do not mix cache keys for different externally provided tokens. |
381 if self._external_token: | 381 if self._external_token: |
382 token_hash = hashlib.sha1(self._external_token.refresh_token).hexdigest() | 382 token_hash = hashlib.sha1(self._external_token.refresh_token).hexdigest() |
383 cache_key = '%s:refresh_tok:%s' % (self._token_cache_key, token_hash) | 383 cache_key = '%s:refresh_tok:%s' % (self._token_cache_key, token_hash) |
384 else: | 384 else: |
385 cache_key = self._token_cache_key | 385 cache_key = self._token_cache_key |
386 logging.debug( | 386 path = _get_token_cache_path() |
387 'Using token storage %r (cache key %r)', OAUTH_TOKENS_CACHE, cache_key) | 387 logging.debug('Using token storage %r (cache key %r)', path, cache_key) |
388 return multistore_file.get_credential_storage_custom_string_key( | 388 return multistore_file.get_credential_storage_custom_string_key( |
389 OAUTH_TOKENS_CACHE, cache_key) | 389 path, cache_key) |
390 | 390 |
391 def _get_cached_credentials(self): | 391 def _get_cached_credentials(self): |
392 """Returns oauth2client.Credentials loaded from storage.""" | 392 """Returns oauth2client.Credentials loaded from storage.""" |
393 storage = self._get_storage() | 393 storage = self._get_storage() |
394 credentials = storage.get() | 394 credentials = storage.get() |
395 | 395 |
396 if not credentials: | 396 if not credentials: |
397 logging.debug('No cached token') | 397 logging.debug('No cached token') |
398 else: | 398 else: |
399 _log_credentials_info('cached token', credentials) | 399 _log_credentials_info('cached token', credentials) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 credentials.token_expiry - datetime.datetime.utcnow()) | 495 credentials.token_expiry - datetime.datetime.utcnow()) |
496 storage = self._get_storage() | 496 storage = self._get_storage() |
497 credentials.set_store(storage) | 497 credentials.set_store(storage) |
498 storage.put(credentials) | 498 storage.put(credentials) |
499 return AccessToken(str(credentials.access_token), credentials.token_expiry) | 499 return AccessToken(str(credentials.access_token), credentials.token_expiry) |
500 | 500 |
501 | 501 |
502 ## Private functions. | 502 ## Private functions. |
503 | 503 |
504 | 504 |
| 505 def _get_token_cache_path(): |
| 506 # On non Win just use HOME. |
| 507 if sys.platform != 'win32': |
| 508 return os.path.join(os.path.expanduser('~'), OAUTH_TOKENS_CACHE) |
| 509 # Prefer USERPROFILE over HOME, since HOME is overridden in |
| 510 # git-..._bin/cmd/git.cmd to point to depot_tools. depot-tools-auth.py script |
| 511 # (and all other scripts) doesn't use this override and thus uses another |
| 512 # value for HOME. git.cmd doesn't touch USERPROFILE though, and usually |
| 513 # USERPROFILE == HOME on Windows. |
| 514 if 'USERPROFILE' in os.environ: |
| 515 return os.path.join(os.environ['USERPROFILE'], OAUTH_TOKENS_CACHE) |
| 516 return os.path.join(os.path.expanduser('~'), OAUTH_TOKENS_CACHE) |
| 517 |
| 518 |
505 def _is_headless(): | 519 def _is_headless(): |
506 """True if machine doesn't seem to have a display.""" | 520 """True if machine doesn't seem to have a display.""" |
507 return sys.platform == 'linux2' and not os.environ.get('DISPLAY') | 521 return sys.platform == 'linux2' and not os.environ.get('DISPLAY') |
508 | 522 |
509 | 523 |
510 def _read_refresh_token_json(path): | 524 def _read_refresh_token_json(path): |
511 """Returns RefreshToken by reading it from the JSON file.""" | 525 """Returns RefreshToken by reading it from the JSON file.""" |
512 try: | 526 try: |
513 with open(path, 'r') as f: | 527 with open(path, 'r') as f: |
514 data = json.load(f) | 528 data = json.load(f) |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 self.end_headers() | 666 self.end_headers() |
653 query = self.path.split('?', 1)[-1] | 667 query = self.path.split('?', 1)[-1] |
654 query = dict(urlparse.parse_qsl(query)) | 668 query = dict(urlparse.parse_qsl(query)) |
655 self.server.query_params = query | 669 self.server.query_params = query |
656 self.wfile.write('<html><head><title>Authentication Status</title></head>') | 670 self.wfile.write('<html><head><title>Authentication Status</title></head>') |
657 self.wfile.write('<body><p>The authentication flow has completed.</p>') | 671 self.wfile.write('<body><p>The authentication flow has completed.</p>') |
658 self.wfile.write('</body></html>') | 672 self.wfile.write('</body></html>') |
659 | 673 |
660 def log_message(self, _format, *args): | 674 def log_message(self, _format, *args): |
661 """Do not log messages to stdout while running as command line program.""" | 675 """Do not log messages to stdout while running as command line program.""" |
OLD | NEW |