def logon(self, username, password, server_url, proxies=None, no_proxy=None, cert_life_time=86400, ssl_ctx=None): """Obtain a new certificate""" if ssl_ctx is None: ssl_ctx = make_ssl_context(ca_dir=self.ca_cert_dir, verify_peer=True, url=server_url, method=SSL.SSLv3_METHOD) # Create a password manager password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() # Get base URL for setting basic auth scope parsed_url = urlparse(server_url) base_url = urlunparse(parsed_url[0:2] + ('/', '', '', '')) # Add the username and password. # If we knew the realm, we could use it instead of ``None``. password_mgr.add_password(None, base_url, username, password) handlers = [urllib2.HTTPBasicAuthHandler(password_mgr)] key_pair = self.__class__.create_key_pair() cert_req = self.__class__.create_cert_req(key_pair) # Convert plus chars to make it safe for HTTP POST encoded_cert_req = cert_req.replace('+', '%2B') req = "%s=%s\n" % (self.__class__.CERT_REQ_POST_PARAM_KEYNAME, encoded_cert_req) config = Configuration(ssl_ctx, True) res = fetch_stream_from_url(server_url, config, data=req, handlers=handlers) return res
def request_resource(self, resource_url, ssl_config=None, config=None, data=None, handlers=None): '''Request a resource URL setting *bearer* token in Authorization header @type resource_url: str @param resource_url: URL of resource to be requested @type ssl_config: ndg.httpsclient.ssl_context_util.SSlContextConfig @param ssl_config: SSL configuration, Nb. if config keyword is set then this parameter will be *ignored* @type config: ndg.httpsclient.utils.Configuration @param config: HTTP configuration settings. Setting this keyword will override any setting made for ssl_config @param data: HTTP POST data @type data: str @param handlers: list of custom urllib2 handlers to add to the request @type handlers: iterable @return: response from resource server @rtype: urllib.addinfourl ''' if self.access_token is None: raise Oauth2ClientConfigError('No access token set for request to ' 'resource %r' % resource_url) authorization_header = { self.__class__.HTTP_AUTHORIZATION_HEADER_FIELD: '%s %s' % ( self.__class__.BEARER_TOK_ID, self.access_token), } if config and ssl_config: raise TypeError('Set either "config" or "ssl_config" keywords but ' 'not both') if config is None: ssl_ctx = ssl_context_util.make_ssl_context_from_config(ssl_config) config = httpsclient_utils.Configuration( ssl_ctx, headers=authorization_header) response = httpsclient_utils.fetch_stream_from_url(resource_url, config, data=data) return response
def request_resource(self, resource_url, ssl_config=None, config=None, data=None, handlers=None): '''Request a resource URL setting *bearer* token in Authorization header @type resource_url: str @param resource_url: URL of resource to be requested @type ssl_config: ndg.httpsclient.ssl_context_util.SSlContextConfig @param ssl_config: SSL configuration, Nb. if config keyword is set then this parameter will be *ignored* @type config: ndg.httpsclient.utils.Configuration @param config: HTTP configuration settings. Setting this keyword will override any setting made for ssl_config @param data: HTTP POST data @type data: str @param handlers: list of custom urllib2 handlers to add to the request @type handlers: iterable @return: response from resource server @rtype: urllib.addinfourl ''' if self.access_token is None: raise Oauth2ClientConfigError('No access token set for request to ' 'resource %r' % resource_url) authorization_header = { self.__class__.HTTP_AUTHORIZATION_HEADER_FIELD: '%s %s' % (self.__class__.BEARER_TOK_ID, self.access_token), } if config and ssl_config: raise TypeError('Set either "config" or "ssl_config" keywords but ' 'not both') if config is None: ssl_ctx = ssl_context_util.make_ssl_context_from_config(ssl_config) config = httpsclient_utils.Configuration( ssl_ctx, headers=authorization_header) response = httpsclient_utils.fetch_stream_from_url(resource_url, config, data=data) return response
def request_access_token(self, code, application_url, request, token_retriever_cb, ssl_config): """ @type code: str @param code: authorization code @type application_url: str @param application_url: application base URL @type request: webob.Request @param request: request object @type token_retriever_cb: callable called with arguments (access_token, error, error_description) @param token_retriever_cb: callable to call when the token is available @type ssl_config: ndg.httpsclient.ssl_context_util.SSlContextConfig @param ssl_config: SSL configuration @rtype: any @return: result from token_retriever_cb """ # Make POST request to obtain an access token. redirect_uri = self.client_config.make_redirect_uri(application_url) parameters = { 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri } # Put client_secret in request when defined. Most implementations # require this as part of the parameters, even though using an # authorization header with a bearer-token would seem to be preferred # by draft-ietf-oauth-v2-bearer-23 if self.client_config.kw.get('client_secret') is not None: parameters['client_id'] = self.client_config.client_id parameters['client_secret'] = self.client_config.kw['client_secret'] self.additional_access_token_request_parameters(parameters, request) log.debug("Requesting access token - parameters: %s", parameters) data = urllib.urlencode(parameters) ssl_ctx = ssl_context_util.make_ssl_context_from_config(ssl_config) # Header required by, for example Github, to get a json response config = httpsclient_utils.Configuration( ssl_ctx, headers={'Accept': 'application/json'}) try: response_json = httpsclient_utils.fetch_stream_from_url( self.client_config.access_token_endpoint, config, data) except HTTPError as http_error: # Expect 400 code if a client error occurred or 500 for server-side # problem. Either way, the following if block should handle this if http_error.code == httplib.BAD_REQUEST: response_json = http_error.fp response = json.load(response_json) access_token = response.get('access_token', None) if 'error' in response: error = response['error'] error_description = response.get('error_description', None) log.error('Access token request error: %s %s', error, error_description) raise Oauth2ClientAccessTokenRetrievalError(error, error_description) elif access_token is None: error = 'invalid_request' error_description = ('Error retrieving access token - ' 'no access token returned.') raise Oauth2ClientAccessTokenRetrievalError(error, error_description) else: self.access_token = access_token.encode(self.ACCESS_TOK_ENCODING) log.debug("Access token received: %s", self.access_token) return token_retriever_cb(self.access_token)
def request_access_token(self, code, application_url, request, token_retriever_cb, ssl_config): """ @type code: str @param code: authorization code @type application_url: str @param application_url: application base URL @type request: webob.Request @param request: request object @type token_retriever_cb: callable called with arguments (access_token, error, error_description) @param token_retriever_cb: callable to call when the token is available @type ssl_config: ndg.httpsclient.ssl_context_util.SSlContextConfig @param ssl_config: SSL configuration @rtype: any @return: result from token_retriever_cb """ # Make POST request to obtain an access token. redirect_uri = self.client_config.make_redirect_uri(application_url) parameters = { 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri } # Put client_secret in request when defined. Most implementations # require this as part of the parameters, even though using an # authorization header with a bearer-token would seem to be preferred # by draft-ietf-oauth-v2-bearer-23 if self.client_config.kw.get('client_secret') is not None: parameters['client_id'] = self.client_config.client_id parameters['client_secret'] = self.client_config.kw[ 'client_secret'] self.additional_access_token_request_parameters(parameters, request) log.debug("Requesting access token - parameters: %s", parameters) data = urllib.urlencode(parameters) ssl_ctx = ssl_context_util.make_ssl_context_from_config(ssl_config) # Header required by, for example Github, to get a json response config = httpsclient_utils.Configuration( ssl_ctx, headers={'Accept': 'application/json'}) try: response_json = httpsclient_utils.fetch_stream_from_url( self.client_config.access_token_endpoint, config, data) except HTTPError as http_error: # Expect 400 code if a client error occurred or 500 for server-side # problem. Either way, the following if block should handle this if http_error.code == httplib.BAD_REQUEST: response_json = http_error.fp response = json.load(response_json) access_token = response.get('access_token', None) if 'error' in response: error = response['error'] error_description = response.get('error_description', None) log.error('Access token request error: %s %s', error, error_description) raise Oauth2ClientAccessTokenRetrievalError( error, error_description) elif access_token is None: error = 'invalid_request' error_description = ('Error retrieving access token - ' 'no access token returned.') raise Oauth2ClientAccessTokenRetrievalError( error, error_description) else: self.access_token = access_token.encode(self.ACCESS_TOK_ENCODING) log.debug("Access token received: %s", self.access_token) return token_retriever_cb(self.access_token)