/src/googlecl/service.py
Python | 142 lines | 78 code | 18 blank | 46 comment | 8 complexity | f3d059d8b5b8c6e089d167c4e9bf0326 MD5 | raw file
1# Copyright (C) 2010 Google Inc. 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 16"""Basic service extensions for the gdata python client library for use on 17 the command line.""" 18 19 20import gdata.service 21import googlecl 22import googlecl.base 23import logging 24 25LOG = logging.getLogger(__name__) 26 27 28class BaseServiceCL(googlecl.base.BaseCL): 29 30 """Extension of gdata.GDataService specific to GoogleCL.""" 31 32 def __init__(self, section, config, 33 request_error_class=gdata.service.RequestError, 34 *args, **kwargs): 35 super(BaseServiceCL, self).__init__(section, 36 config, 37 request_error_class, 38 *args, 39 **kwargs) 40 # Most services using old gdata API have to disable ssl. 41 self.ssl = False 42 43 # Used for automatic retries of Get/Delete requests that fail due to 302 44 # errors. See BaseCL.retry_operation. 45 self.original_get = self.Get 46 self.original_delete = self.Delete 47 self.original_post = self.Post 48 self.original_put = self.Put 49 self.Get = self.retry_get 50 self.Delete = self.retry_delete 51 self.Post = self.retry_post 52 self.Put = self.retry_put 53 54 LOG.debug('Initialized googlecl.service.BaseServiceCL') 55 56 def retry_get(self, *args, **kwargs): 57 """Retries the Get method.""" 58 self.original_operation = self.original_get 59 return self.retry_operation(*args, **kwargs) 60 61 def retry_delete(self, *args, **kwargs): 62 """Retries the Delete method.""" 63 self.original_operation = self.original_delete 64 return self.retry_operation(*args, **kwargs) 65 66 def retry_post(self, *args, **kwargs): 67 """Retries the Post method.""" 68 self.original_operation = self.original_post 69 return self.retry_operation(*args, **kwargs) 70 71 def retry_put(self, *args, **kwargs): 72 """Retries the Put method.""" 73 self.original_operation = self.original_put 74 return self.retry_operation(*args, **kwargs) 75 76 def request_access(self, domain, display_name, scopes=None, browser=None): 77 """Do all the steps involved with getting an OAuth access token. 78 79 Keyword arguments: 80 domain: Domain to request access for. 81 (Sets the hd query parameter for the authorization step). 82 display_name: Descriptor for the machine doing the requesting. 83 scopes: String or list/tuple of strings describing scopes to request 84 access to. Default None for default scope of service. 85 browser: Browser to use to open authentication request url. Default None 86 for no browser launch, and just displaying the url. 87 88 Returns: 89 True if access token was succesfully retrieved and set, otherwise False. 90 91 """ 92 # Installed applications do not have a pre-registration and so follow 93 # directions for unregistered applications 94 self.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1, 95 consumer_key='anonymous', 96 consumer_secret='anonymous') 97 fetch_params = {'xoauth_displayname':display_name} 98 # First and third if statements taken from 99 # gdata.service.GDataService.FetchOAuthRequestToken. 100 # Need to do this detection/conversion here so we can add the 'email' API 101 if not scopes: 102 scopes = gdata.service.lookup_scopes(self.service) 103 if isinstance(scopes, tuple): 104 scopes = list(scopes) 105 if not isinstance(scopes, list): 106 scopes = [scopes,] 107 scopes.extend(['https://www.googleapis.com/auth/userinfo#email']) 108 LOG.debug('Scopes being requested: ' + str(scopes)) 109 110 try: 111 request_token = self.FetchOAuthRequestToken(scopes=scopes, 112 extra_parameters=fetch_params) 113 except gdata.service.FetchingOAuthRequestTokenFailed, err: 114 LOG.error(err[0]['body'].strip() + '; Request token retrieval failed!') 115 if str(err).find('Timestamp') != -1: 116 LOG.info('Is your system clock up to date? See the FAQ on our wiki: ' 117 'http://code.google.com/p/googlecl/wiki/FAQ' 118 '#Timestamp_too_far_from_current_time') 119 return False 120 auth_params = {'hd': domain} 121 auth_url = self.GenerateOAuthAuthorizationURL(request_token=request_token, 122 extra_params=auth_params) 123 if browser is not None: 124 try: 125 browser.open(str(auth_url)) 126 except Exception, err: 127 # Blanket catch of Exception is a bad idea, but don't want to pass in 128 # error to look for. 129 LOG.error('Failed to launch web browser: ' + unicode(err)) 130 message = ('Please log in and/or grant access via your browser at: \n%s\n\n' 131 'Then, in this terminal, hit enter. ' % auth_url) 132 raw_input(message) 133 # This upgrades the token, and if successful, sets the access token 134 try: 135 self.UpgradeToOAuthAccessToken(request_token) 136 except gdata.service.TokenUpgradeFailed: 137 LOG.error('Token upgrade failed! Could not get OAuth access token.') 138 return False 139 else: 140 return True 141 142 RequestAccess = request_access