Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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)
Esempio n. 4
0
    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)