blob: 84ba62cd4438bf8d451e992aa8a7844b5598b1ca [file] [log] [blame]
# Copyright 2014 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."""
from __future__ import absolute_import
import json
import os
import sys
import time
import webbrowser
from oauth2client.client import OAuth2WebServerFlow
from gcs_oauth2_boto_plugin import oauth2_client
CLIENT_ID = None
CLIENT_SECRET = None
GOOGLE_OAUTH2_PROVIDER_AUTHORIZATION_URI = (
'https://accounts.google.com/o/oauth2/auth')
GOOGLE_OAUTH2_PROVIDER_TOKEN_URI = (
'https://accounts.google.com/o/oauth2/token')
GOOGLE_OAUTH2_DEFAULT_FILE_PASSWORD = 'notasecret'
OOB_REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
def OAuth2ClientFromBotoConfig(
config, cred_type=oauth2_client.CredTypes.OAUTH2_USER_ACCOUNT):
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_host = None
proxy_port = None
proxy_user = None
proxy_pass = None
if (config.has_option('Boto', 'proxy')
and config.has_option('Boto', 'proxy_port')):
proxy_host = config.get('Boto', 'proxy')
proxy_port = int(config.get('Boto', 'proxy_port'))
proxy_user = config.get('Boto', 'proxy_user', None)
proxy_pass = config.get('Boto', 'proxy_pass', None)
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)
if cred_type == oauth2_client.CredTypes.OAUTH2_SERVICE_ACCOUNT:
service_client_id = config.get('Credentials', 'gs_service_client_id', '')
private_key_filename = config.get('Credentials', 'gs_service_key_file', '')
with open(private_key_filename, 'rb') as private_key_file:
private_key = private_key_file.read()
json_key = None
try:
json_key = json.loads(private_key)
except ValueError:
pass
if json_key:
for json_entry in ('client_id', 'client_email', 'private_key_id',
'private_key'):
if json_entry not in json_key:
raise Exception('The JSON private key file at %s '
'did not contain the required entry: %s' %
(private_key_filename, json_entry))
return oauth2_client.OAuth2JsonServiceAccountClient(
json_key['client_id'], json_key['client_email'],
json_key['private_key_id'], json_key['private_key'],
access_token_cache=token_cache, auth_uri=provider_authorization_uri,
token_uri=provider_token_uri,
disable_ssl_certificate_validation=not(config.getbool(
'Boto', 'https_validate_certificates', True)),
proxy_host=proxy_host, proxy_port=proxy_port,
proxy_user=proxy_user, proxy_pass=proxy_pass)
else:
key_file_pass = config.get('Credentials', 'gs_service_key_file_password',
GOOGLE_OAUTH2_DEFAULT_FILE_PASSWORD)
return oauth2_client.OAuth2ServiceAccountClient(
service_client_id, private_key, key_file_pass,
access_token_cache=token_cache, auth_uri=provider_authorization_uri,
token_uri=provider_token_uri,
disable_ssl_certificate_validation=not(config.getbool(
'Boto', 'https_validate_certificates', True)),
proxy_host=proxy_host, proxy_port=proxy_port,
proxy_user=proxy_user, proxy_pass=proxy_pass)
elif cred_type == oauth2_client.CredTypes.OAUTH2_USER_ACCOUNT:
client_id = config.get('OAuth2', 'client_id',
os.environ.get('OAUTH2_CLIENT_ID', CLIENT_ID))
if not client_id:
raise Exception(
'client_id for your application obtained from '
'https://console.developers.google.com must be set in a boto config '
'or with OAUTH2_CLIENT_ID environment variable or with '
'gcs_oauth2_boto_plugin.SetFallbackClientIdAndSecret function.')
client_secret = config.get('OAuth2', 'client_secret',
os.environ.get('OAUTH2_CLIENT_SECRET',
CLIENT_SECRET))
ca_certs_file=config.get_value('Boto', 'ca_certificates_file')
if ca_certs_file == 'system':
ca_certs_file = None
if not client_secret:
raise Exception(
'client_secret for your application obtained from '
'https://console.developers.google.com must be set in a boto config '
'or with OAUTH2_CLIENT_SECRET environment variable or with '
'gcs_oauth2_boto_plugin.SetFallbackClientIdAndSecret function.')
return oauth2_client.OAuth2UserAccountClient(
provider_token_uri, client_id, client_secret,
config.get('Credentials', 'gs_oauth2_refresh_token'),
auth_uri=provider_authorization_uri, access_token_cache=token_cache,
disable_ssl_certificate_validation=not(config.getbool(
'Boto', 'https_validate_certificates', True)),
proxy_host=proxy_host, proxy_port=proxy_port,
proxy_user=proxy_user, proxy_pass=proxy_pass,
ca_certs_file=ca_certs_file)
else:
raise Exception('You have attempted to create an OAuth2 client without '
'setting up OAuth2 credentials.')
def OAuth2ApprovalFlow(client, scopes, launch_browser=False):
flow = OAuth2WebServerFlow(
client.client_id, client.client_secret, scopes, auth_uri=client.auth_uri,
token_uri=client.token_uri, redirect_uri=OOB_REDIRECT_URI)
approval_url = flow.step1_get_authorize_url()
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\ncallable [...] 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' %
approval_url)
sys.stdout.write(
'In your browser you should see a page that requests you to authorize '
'access to Google Cloud Platform APIs and Services on your behalf. '
'After you approve, an authorization code will be displayed.\n\n')
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)
# Short delay; webbrowser.open on linux insists on printing out a message
# which we don't want to run into the prompt for the auth code.
time.sleep(2)
code = raw_input('Enter the authorization code: ')
credentials = flow.step2_exchange(code, http=client.CreateHttpRequest())
return credentials.refresh_token
def SetFallbackClientIdAndSecret(client_id, client_secret):
global CLIENT_ID
global CLIENT_SECRET
CLIENT_ID = client_id
CLIENT_SECRET = client_secret
def SetLock(lock):
oauth2_client.token_exchange_lock = lock