| OLD | NEW |
| (Empty) |
| 1 # Copyright 2011 Google Inc. All Rights Reserved. | |
| 2 # | |
| 3 # Licensed under the Apache License, Version 2.0 (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 | |
| 6 # | |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 # | |
| 9 # Unless required by applicable law or agreed to in writing, software | |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 # See the License for the specific language governing permissions and | |
| 13 # limitations under the License. | |
| 14 | |
| 15 """Helper routines to facilitate use of oauth2_client in gsutil.""" | |
| 16 | |
| 17 import boto | |
| 18 import sys | |
| 19 import time | |
| 20 import webbrowser | |
| 21 | |
| 22 from gslib.cred_types import CredTypes | |
| 23 import oauth2_client | |
| 24 from oauth2client.client import OAuth2WebServerFlow | |
| 25 from oauth2client.file import Storage | |
| 26 | |
| 27 | |
| 28 | |
| 29 GSUTIL_CLIENT_ID = '909320924072.apps.googleusercontent.com' | |
| 30 # Google OAuth2 clients always have a secret, even if the client is an installed | |
| 31 # application/utility such as gsutil. Of course, in such cases the "secret" is | |
| 32 # actually publicly known; security depends entirely on the secrecy of refresh | |
| 33 # tokens, which effectively become bearer tokens. | |
| 34 GSUTIL_CLIENT_NOTSOSECRET = 'p3RlpR10xMFh9ZXBS/ZNLYUu' | |
| 35 | |
| 36 GOOGLE_OAUTH2_PROVIDER_LABEL = 'Google' | |
| 37 GOOGLE_OAUTH2_PROVIDER_AUTHORIZATION_URI = ( | |
| 38 'https://accounts.google.com/o/oauth2/auth') | |
| 39 GOOGLE_OAUTH2_PROVIDER_TOKEN_URI = ( | |
| 40 'https://accounts.google.com/o/oauth2/token') | |
| 41 GOOGLE_OAUTH2_DEFAULT_FILE_PASSWORD = 'notasecret' | |
| 42 | |
| 43 OOB_REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' | |
| 44 | |
| 45 def OAuth2ClientFromBotoConfig(config, | |
| 46 cred_type=CredTypes.OAUTH2_USER_ACCOUNT): | |
| 47 token_cache = None | |
| 48 token_cache_type = config.get('OAuth2', 'token_cache', 'file_system') | |
| 49 if token_cache_type == 'file_system': | |
| 50 if config.has_option('OAuth2', 'token_cache_path_pattern'): | |
| 51 token_cache = oauth2_client.FileSystemTokenCache( | |
| 52 path_pattern=config.get('OAuth2', 'token_cache_path_pattern')) | |
| 53 else: | |
| 54 token_cache = oauth2_client.FileSystemTokenCache() | |
| 55 elif token_cache_type == 'in_memory': | |
| 56 token_cache = oauth2_client.InMemoryTokenCache() | |
| 57 else: | |
| 58 raise Exception( | |
| 59 "Invalid value for config option OAuth2/token_cache: %s" % | |
| 60 token_cache_type) | |
| 61 | |
| 62 proxy_host = None | |
| 63 proxy_port = None | |
| 64 if (config.has_option('Boto', 'proxy') | |
| 65 and config.has_option('Boto', 'proxy_port')): | |
| 66 proxy_host = config.get('Boto', 'proxy') | |
| 67 proxy_port = int(config.get('Boto', 'proxy_port')) | |
| 68 | |
| 69 provider_label = config.get( | |
| 70 'OAuth2', 'provider_label', GOOGLE_OAUTH2_PROVIDER_LABEL) | |
| 71 provider_authorization_uri = config.get( | |
| 72 'OAuth2', 'provider_authorization_uri', | |
| 73 GOOGLE_OAUTH2_PROVIDER_AUTHORIZATION_URI) | |
| 74 provider_token_uri = config.get( | |
| 75 'OAuth2', 'provider_token_uri', GOOGLE_OAUTH2_PROVIDER_TOKEN_URI) | |
| 76 | |
| 77 if cred_type == CredTypes.OAUTH2_SERVICE_ACCOUNT: | |
| 78 service_client_id = config.get('Credentials', 'gs_service_client_id', '') | |
| 79 private_key_filename = config.get('Credentials', 'gs_service_key_file', '') | |
| 80 key_file_pass = config.get('Credentials', 'gs_service_key_file_password', | |
| 81 GOOGLE_OAUTH2_DEFAULT_FILE_PASSWORD) | |
| 82 with open(private_key_filename, 'rb') as private_key_file: | |
| 83 private_key = private_key_file.read() | |
| 84 | |
| 85 return oauth2_client.OAuth2ServiceAccountClient(service_client_id, | |
| 86 private_key, key_file_pass, access_token_cache=token_cache, | |
| 87 auth_uri=provider_authorization_uri, token_uri=provider_token_uri, | |
| 88 disable_ssl_certificate_validation=not(config.getbool( | |
| 89 'Boto', 'https_validate_certificates', True)), | |
| 90 proxy_host=proxy_host, proxy_port=proxy_port) | |
| 91 | |
| 92 elif cred_type == CredTypes.OAUTH2_USER_ACCOUNT: | |
| 93 client_id = config.get('OAuth2', 'client_id', GSUTIL_CLIENT_ID) | |
| 94 client_secret = config.get( | |
| 95 'OAuth2', 'client_secret', GSUTIL_CLIENT_NOTSOSECRET) | |
| 96 return oauth2_client.OAuth2UserAccountClient( | |
| 97 provider_token_uri, client_id, client_secret, | |
| 98 config.get('Credentials', 'gs_oauth2_refresh_token'), | |
| 99 auth_uri=provider_authorization_uri, | |
| 100 access_token_cache=token_cache, | |
| 101 disable_ssl_certificate_validation=not(config.getbool( | |
| 102 'Boto', 'https_validate_certificates', True)), | |
| 103 proxy_host=proxy_host, proxy_port=proxy_port, | |
| 104 ca_certs_file=config.get_value('Boto', 'ca_certificates_file')) | |
| 105 else: | |
| 106 raise Exception('You have attempted to create an OAuth2 client without ' | |
| 107 'setting up OAuth2 credentials. Please run "gsutil config" to set up ' | |
| 108 'your credentials correctly or see "gsutil help config" for more ' | |
| 109 'information.') | |
| 110 | |
| 111 | |
| 112 def OAuth2ApprovalFlow(oauth2_client, scopes, launch_browser=False): | |
| 113 flow = OAuth2WebServerFlow( | |
| 114 oauth2_client.client_id, oauth2_client.client_secret, scopes, | |
| 115 auth_uri=oauth2_client.auth_uri, token_uri=oauth2_client.token_uri, | |
| 116 redirect_uri=OOB_REDIRECT_URI) | |
| 117 approval_url = flow.step1_get_authorize_url() | |
| 118 | |
| 119 if launch_browser: | |
| 120 sys.stdout.write( | |
| 121 'Attempting to launch a browser with the OAuth2 approval dialog at ' | |
| 122 'URL: %s\n\n' | |
| 123 '[Note: due to a Python bug, you may see a spurious error message ' | |
| 124 '"object is not\ncallable [...] in [...] Popen.__del__" which can be ' | |
| 125 'ignored.]\n\n' % approval_url) | |
| 126 else: | |
| 127 sys.stdout.write( | |
| 128 'Please navigate your browser to the following URL:\n%s\n' % | |
| 129 approval_url) | |
| 130 | |
| 131 sys.stdout.write( | |
| 132 'In your browser you should see a page that requests you to authorize ' | |
| 133 'gsutil to access\nGoogle Cloud Storage on your behalf. After you ' | |
| 134 'approve, an authorization code will be displayed.\n\n') | |
| 135 if (launch_browser and | |
| 136 not webbrowser.open(approval_url, new=1, autoraise=True)): | |
| 137 sys.stdout.write( | |
| 138 'Launching browser appears to have failed; please navigate a browser ' | |
| 139 'to the following URL:\n%s\n' % approval_url) | |
| 140 # Short delay; webbrowser.open on linux insists on printing out a message | |
| 141 # which we don't want to run into the prompt for the auth code. | |
| 142 time.sleep(2) | |
| 143 code = raw_input('Enter the authorization code: ') | |
| 144 credentials = flow.step2_exchange(code, | |
| 145 http=oauth2_client.CreateHttpRequest()) | |
| 146 return credentials.refresh_token | |
| OLD | NEW |