Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: third_party/gsutil/oauth2_plugin/oauth2_client.py

Issue 10199002: Upgrade gsutil to 3.4 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed comments Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2010 Google Inc. 1 # Copyright 2010 Google Inc.
2 # 2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 5 # You may obtain a copy of the License at
6 # 6 #
7 # http://www.apache.org/licenses/LICENSE-2.0 7 # http://www.apache.org/licenses/LICENSE-2.0
8 # 8 #
9 # Unless required by applicable law or agreed to in writing, software 9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 10 # distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 24 matching lines...) Expand all
35 # encapsulates both refresh and access tokens). 35 # encapsulates both refresh and access tokens).
36 36
37 37
38 import cgi 38 import cgi
39 import datetime 39 import datetime
40 import errno 40 import errno
41 from hashlib import sha1 41 from hashlib import sha1
42 import logging 42 import logging
43 import os 43 import os
44 import tempfile 44 import tempfile
45 import threading
45 import urllib 46 import urllib
46 import urllib2 47 import urllib2
47 import urlparse 48 import urlparse
48 49
49 from boto import cacerts 50 from boto import cacerts
50 from third_party import fancy_urllib 51 from third_party import fancy_urllib
51 52
52 try: 53 try:
53 import json 54 import json
54 except ImportError: 55 except ImportError:
55 try: 56 try:
56 # Try to import from django, should work on App Engine 57 # Try to import from django, should work on App Engine
57 from django.utils import simplejson as json 58 from django.utils import simplejson as json
58 except ImportError: 59 except ImportError:
59 # Try for simplejson 60 # Try for simplejson
60 import simplejson as json 61 import simplejson as json
61 62
62 LOG = logging.getLogger('oauth2_client') 63 LOG = logging.getLogger('oauth2_client')
64 # Lock used for checking/exchanging refresh token, so multithreaded
65 # operation doesn't attempt concurrent refreshes.
66 token_exchange_lock = threading.Lock()
63 67
64 # SHA1 sum of the CA certificates file imported from boto. 68 # SHA1 sum of the CA certificates file imported from boto.
65 CACERTS_FILE_SHA1SUM = 'ed024a78d9327f8669b3b117d9eac9e3c9460e9b' 69 CACERTS_FILE_SHA1SUM = 'ed024a78d9327f8669b3b117d9eac9e3c9460e9b'
66 70
67 class Error(Exception): 71 class Error(Exception):
68 """Base exception for the OAuth2 module.""" 72 """Base exception for the OAuth2 module."""
69 pass 73 pass
70 74
71 75
72 class AccessTokenRefreshError(Error): 76 class AccessTokenRefreshError(Error):
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 found, the client obtains a fresh access token for the provided refresh 362 found, the client obtains a fresh access token for the provided refresh
359 token from the OAuth2 provider's token endpoint. 363 token from the OAuth2 provider's token endpoint.
360 364
361 Args: 365 Args:
362 refresh_token: The RefreshToken object which to get an access token for. 366 refresh_token: The RefreshToken object which to get an access token for.
363 Returns: 367 Returns:
364 The cached or freshly obtained AccessToken. 368 The cached or freshly obtained AccessToken.
365 Raises: 369 Raises:
366 AccessTokenRefreshError if an error occurs. 370 AccessTokenRefreshError if an error occurs.
367 """ 371 """
368 cache_key = refresh_token.CacheKey() 372 # Ensure only one thread at a time attempts to get (and possibly refresh)
369 LOG.info('GetAccessToken: checking cache for key %s', cache_key) 373 # the access token. This doesn't prevent concurrent refresh attempts across
370 access_token = self.access_token_cache.GetToken(cache_key) 374 # multiple gsutil instances, but at least protects against multiple threads
371 LOG.debug('GetAccessToken: token from cache: %s', access_token) 375 # simultaneously attempting to refresh when gsutil -m is used.
372 if access_token is None or access_token.ShouldRefresh(): 376 token_exchange_lock.acquire()
373 LOG.info('GetAccessToken: fetching fresh access token...') 377 try:
374 access_token = self.FetchAccessToken(refresh_token) 378 cache_key = refresh_token.CacheKey()
375 LOG.debug('GetAccessToken: fresh access token: %s', access_token) 379 LOG.info('GetAccessToken: checking cache for key %s', cache_key)
376 self.access_token_cache.PutToken(cache_key, access_token) 380 access_token = self.access_token_cache.GetToken(cache_key)
377 return access_token 381 LOG.debug('GetAccessToken: token from cache: %s', access_token)
382 if access_token is None or access_token.ShouldRefresh():
383 LOG.info('GetAccessToken: fetching fresh access token...')
384 access_token = self.FetchAccessToken(refresh_token)
385 LOG.debug('GetAccessToken: fresh access token: %s', access_token)
386 self.access_token_cache.PutToken(cache_key, access_token)
387 return access_token
388 finally:
389 token_exchange_lock.release()
378 390
379 def FetchAccessToken(self, refresh_token): 391 def FetchAccessToken(self, refresh_token):
380 """Fetches an access token from the provider's token endpoint. 392 """Fetches an access token from the provider's token endpoint.
381 393
382 Given a RefreshToken, fetches an access token from this client's OAuth2 394 Given a RefreshToken, fetches an access token from this client's OAuth2
383 provider's token endpoint. 395 provider's token endpoint.
384 396
385 Args: 397 Args:
386 refresh_token: The RefreshToken object which to get an access token for. 398 refresh_token: The RefreshToken object which to get an access token for.
387 Returns: 399 Returns:
388 The fetched AccessToken. 400 The fetched AccessToken.
389 Raises: 401 Raises:
390 AccessTokenRefreshError: if an error occurs. 402 AccessTokenRefreshError: if an error occurs.
391 """ 403 """
392 request = { 404 request = {
393 'grant_type': 'refresh_token', 405 'grant_type': 'refresh_token',
394 'client_id': self.client_id, 406 'client_id': self.client_id,
395 'client_secret': self.client_secret, 407 'client_secret': self.client_secret,
396 'refresh_token': refresh_token.refresh_token, 408 'refresh_token': refresh_token.refresh_token,
397 } 409 }
398 LOG.debug('FetchAccessToken request: %s', request) 410 LOG.debug('FetchAccessToken request: %s', request)
399 411
400 response, error = self._TokenRequest(request) 412 response, error = self._TokenRequest(request)
401 LOG.debug( 413 LOG.debug(
402 'FetchAccessToken response (error = %s): %s', error, response) 414 'FetchAccessToken response (error = %s): %s', error, response)
403 415
404 if error: 416 if error:
405 oauth2_error = '' 417 oauth2_error = ''
406 if response and response['error']: 418 if response and response['error']:
407 oauth2_error = '; OAuth2 error: %s', response['error'] 419 oauth2_error = '; OAuth2 error: %s' % response['error']
408 raise AccessTokenRefreshError( 420 raise AccessTokenRefreshError(
409 'Failed to exchange refresh token into access token; ' 421 'Failed to exchange refresh token into access token; '
410 'request failed: %s%s', error, oauth2_error) 422 'request failed: %s%s' % (error, oauth2_error))
411 423
412 if 'access_token' not in response: 424 if 'access_token' not in response:
413 raise AccessTokenRefreshError( 425 raise AccessTokenRefreshError(
414 'Failed to exchange refresh token into access token; response: %s', 426 'Failed to exchange refresh token into access token; response: %s' %
415 response) 427 response)
416 428
417 token_expiry = None 429 token_expiry = None
418 if 'expires_in' in response: 430 if 'expires_in' in response:
419 token_expiry = ( 431 token_expiry = (
420 self.datetime_strategy.utcnow() + 432 self.datetime_strategy.utcnow() +
421 datetime.timedelta(seconds=int(response['expires_in']))) 433 datetime.timedelta(seconds=int(response['expires_in'])))
422 434
423 return AccessToken(response['access_token'], token_expiry, 435 return AccessToken(response['access_token'], token_expiry,
424 datetime_strategy=self.datetime_strategy) 436 datetime_strategy=self.datetime_strategy)
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 LOG.debug('ExchangeAuthorizationCode request: %s', request) 507 LOG.debug('ExchangeAuthorizationCode request: %s', request)
496 508
497 response, error = self._TokenRequest(request) 509 response, error = self._TokenRequest(request)
498 LOG.debug( 510 LOG.debug(
499 'ExchangeAuthorizationCode response (error = %s): %s', 511 'ExchangeAuthorizationCode response (error = %s): %s',
500 error, response) 512 error, response)
501 513
502 if error: 514 if error:
503 oauth2_error = '' 515 oauth2_error = ''
504 if response and response['error']: 516 if response and response['error']:
505 oauth2_error = '; OAuth2 error: %s', response['error'] 517 oauth2_error = '; OAuth2 error: %s' % response['error']
506 raise AuthorizationCodeExchangeError( 518 raise AuthorizationCodeExchangeError(
507 'Failed to exchange refresh token into access token; ' 519 'Failed to exchange refresh token into access token; '
508 'request failed: %s%s', error, oauth2_error) 520 'request failed: %s%s' % (str(error), oauth2_error))
509 521
510 if not 'access_token' in response: 522 if not 'access_token' in response:
511 raise AuthorizationCodeExchangeError( 523 raise AuthorizationCodeExchangeError(
512 'Failed to exchange authorization code into access token; ' 524 'Failed to exchange authorization code into access token; '
513 'response: %s', response) 525 'response: %s' % response)
514 526
515 token_expiry = None 527 token_expiry = None
516 if 'expires_in' in response: 528 if 'expires_in' in response:
517 token_expiry = ( 529 token_expiry = (
518 self.datetime_strategy.utcnow() + 530 self.datetime_strategy.utcnow() +
519 datetime.timedelta(seconds=int(response['expires_in']))) 531 datetime.timedelta(seconds=int(response['expires_in'])))
520 532
521 access_token = AccessToken(response['access_token'], token_expiry, 533 access_token = AccessToken(response['access_token'], token_expiry,
522 datetime_strategy=self.datetime_strategy) 534 datetime_strategy=self.datetime_strategy)
523 535
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 h.update(self.refresh_token) 628 h.update(self.refresh_token)
617 return h.hexdigest() 629 return h.hexdigest()
618 630
619 def GetAuthorizationHeader(self): 631 def GetAuthorizationHeader(self):
620 """Gets the access token HTTP authorication header value. 632 """Gets the access token HTTP authorication header value.
621 633
622 Returns: 634 Returns:
623 The value of an Authorization HTTP header that authenticates 635 The value of an Authorization HTTP header that authenticates
624 requests with an OAuth2 access token based on this refresh token. 636 requests with an OAuth2 access token based on this refresh token.
625 """ 637 """
626 return 'OAuth %s' % self.oauth2_client.GetAccessToken(self).token 638 return 'Bearer %s' % self.oauth2_client.GetAccessToken(self).token
OLDNEW
« no previous file with comments | « third_party/gsutil/oauth2_plugin/__init__.py ('k') | third_party/gsutil/oauth2_plugin/oauth2_client_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698