Пример #1
0
    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
Пример #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
Пример #3
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
Пример #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)
Пример #5
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)