# Copyright 2011 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Helper routines to facilitate use of oauth2_client in gsutil.""" import sys import time import webbrowser import oauth2_client GSUTIL_CLIENT_ID = '909320924072.apps.googleusercontent.com' # Google OAuth2 clients always have a secret, even if the client is an installed # application/utility such as gsutil. Of course, in such cases the "secret" is # actually publicly known; security depends entirly on the secrecy of refresh # tokens, which effectively become bearer tokens. GSUTIL_CLIENT_NOTSOSECRET = 'p3RlpR10xMFh9ZXBS/ZNLYUu' GOOGLE_OAUTH2_PROVIDER_LABEL = 'Google' GOOGLE_OAUTH2_PROVIDER_AUTHORIZATION_URI = ( 'https://accounts.google.com/o/oauth2/auth') GOOGLE_OAUTH2_PROVIDER_TOKEN_URI = ( 'https://accounts.google.com/o/oauth2/token') OOB_REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' def OAuth2ClientFromBotoConfig(config): token_cache = None token_cache_type = config.get('OAuth2', 'token_cache', 'file_system') if token_cache_type == 'file_system': if config.has_option('OAuth2', 'token_cache_path_pattern'): token_cache = oauth2_client.FileSystemTokenCache( path_pattern=config.get('OAuth2', 'token_cache_path_pattern')) else: token_cache = oauth2_client.FileSystemTokenCache() elif token_cache_type == 'in_memory': token_cache = oauth2_client.InMemoryTokenCache() else: raise Exception( "Invalid value for config option OAuth2/token_cache: %s" % token_cache_type) proxy = None if (config.has_option('Boto', 'proxy') and config.has_option('Boto', 'proxy_port')): proxy = "%s:%s" % (config.get('Boto', 'proxy'), config.get('Boto', 'proxy_port')) provider_label = config.get( 'OAuth2', 'provider_label', GOOGLE_OAUTH2_PROVIDER_LABEL) provider_authorization_uri = config.get( 'OAuth2', 'provider_authorization_uri', GOOGLE_OAUTH2_PROVIDER_AUTHORIZATION_URI) provider_token_uri = config.get( 'OAuth2', 'provider_token_uri', GOOGLE_OAUTH2_PROVIDER_TOKEN_URI) client_id = config.get('OAuth2', 'client_id', GSUTIL_CLIENT_ID) client_secret = config.get( 'OAuth2', 'client_secret', GSUTIL_CLIENT_NOTSOSECRET) return oauth2_client.OAuth2Client( oauth2_client.OAuth2Provider( provider_label, provider_authorization_uri, provider_token_uri), client_id, client_secret, proxy=proxy, access_token_cache=token_cache) def OAuth2ApprovalFlow(oauth2_client, scopes, launch_browser=False): approval_url = oauth2_client.GetAuthorizationUri(OOB_REDIRECT_URI, scopes) if launch_browser: sys.stdout.write( 'Attempting to launch a browser with the OAuth2 approval dialog at ' 'URL: %s\n\n' '[Note: due to a Python bug, you may see a spurious error message "object is not\n' 'callable [...] in [...] Popen.__del__" which can be ignored.]\n\n' % approval_url) else: sys.stdout.write( 'Please navigate your browser to the following URL:\n%s\n\n' % approval_url) if (launch_browser and not webbrowser.open(approval_url, new=1, autoraise=True)): sys.stdout.write( 'Launching browser appears to have failed; please navigate a browser ' 'to the following URL:\n%s\n' % approval_url) code = raw_input('Enter the authorization code: ') refresh_token, access_token = oauth2_client.ExchangeAuthorizationCode( code, OOB_REDIRECT_URI, scopes) return refresh_token