Esempio n. 1
0
    def validate_token_request(self, request):
        # We need to set these at None by default otherwise
        # we are going to get some AttributeError later
        request._params.setdefault("backend", None)
        request._params.setdefault("client_secret", None)

        if request.grant_type != 'convert_token':
            raise errors.UnsupportedGrantTypeError(request=request)

        # We check that a token parameter is present.
        # It should contain the social token to be used with the backend
        if request.token is None:
            raise errors.InvalidRequestError(
                description='Missing token parameter.', request=request)

        # We check that a provider parameter is present.
        # It should contain the name of the social provider to be used
        if request.provider is None:
            raise errors.InvalidRequestError(
                description='Missing provider parameter.', request=request)

        if not request.client_id:
            raise errors.MissingClientIdError(request=request)

        if not self.request_validator.validate_client_id(
                request.client_id, request):
            raise errors.InvalidClientIdError(request=request)

        # Existing code to retrieve the application instance from the client id
        if self.request_validator.client_authentication_required(request):
            logger.debug('Authenticating client, %r.', request)
            if not self.request_validator.authenticate_client(request):
                logger.debug('Invalid client (%r), denying access.', request)
                raise errors.InvalidClientError(request=request)
        elif not self.request_validator.authenticate_client_id(
                request.client_id, request):
            logger.debug('Client authentication failed, %r.', request)
            raise errors.InvalidClientError(request=request)

        # Ensure client is authorized use of this grant type
        # We chose refresh_token as a grant_type
        # as we don't want to modify all the codebase.
        # It is also the most permissive and logical grant for our needs.
        request.grant_type = "refresh_token"
        self.validate_grant_type(request)
        self.validate_scopes(request)

        # TODO: Implement logic to decide whether or not to grant the access_token
        # Decoded body is a list of tuple, dict is better
        body = {}
        for t in request.decoded_body:
            body[t[0]] = t[1]

        user = get_user_by_access_token(token=body['token'],
                                        provider=body['provider'],
                                        nonce=body['nonce'])
        if user is None:
            raise errors.InvalidClientError(
                "Authentication token for the given provider is invalid")
        request.user = user
Esempio n. 2
0
    def external_validator(self, provider, access_code, request):
        """
        Calls the social backend to validate the access_code
        and get information
        """
        strategy = load_strategy(request=get_request())
        log.debug('Loading provider backend %s.', request.provider)
        try:
            backend = load_backend(
                strategy, provider, reverse(
                    "%s:complete" %
                    NAMESPACE, args=(
                        provider,)))
        except MissingBackend:
            raise errors.InvalidRequestError(
                description='Invalid provider given',
                request=request)
        log.debug(
            'Dispatching authentication to provider %s.',
            request.provider)
        try:
            user = backend.do_auth(access_token=request.access_token)
        except requests.HTTPError as e:
            raise errors.InvalidRequestError(
                description="Backend responded with HTTP{0}: {1}.".format(
                    e.response.status_code, e.response.text), request=request)

        if not user:
            raise errors.InvalidGrantError(
                'Invalid access-code', request=request)
        if not user.is_active:
            raise errors.InvalidGrantError('User inactive', request=request)
        request.user = user
        return True
Esempio n. 3
0
    def early_validate_token_request(self, request):
        for attr in self.mandatory_parameters:
            if not getattr(request, attr):
                raise errors.InvalidRequestError(
                    'Request is missing parameter %s.' % attr, request=request)

        if request.grant_type not in self.grant_types:
            raise errors.UnsupportedGrantTypeError(request=request)

        for param in self.disallowed_duplicates:
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(
                    description='Duplicate %s parameter.' % param,
                    request=request)
Esempio n. 4
0
    def validate_token_request(self, request):
        if request.grant_type != JWT_BEARER:
            raise errors.UnsupportedGrantTypeError(request=request)

        if request.assertion is None:
            raise errors.InvalidRequestError('Missing assertion parameter.',
                                             request=request)

        for param in ('grant_type', 'scope'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError('Duplicate %s parameter.' %
                                                 param,
                                                 request=request)

        # Since the JSON Web Token is signed by its issuer client
        # authentication is not strictly required when the token is used as
        # an authorization grant. However, if client credentials are provided
        # they should be validated as describe in Section 3.1.
        # https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12#section-3.1
        if self.request_validator.client_authentication_required(request):
            log.debug('Authenticating client, %r.', request)
            if not self.request_validator.authenticate_client(request):
                log.debug('Invalid client (%r), denying access.', request)
                raise errors.InvalidClientError(request=request)

        # REQUIRED. The web token issued by the client.
        log.debug('Validating assertion %s.', request.assertion)
        if not self.request_validator.validate_bearer_token(
                request.assertion, request.scopes, request):
            log.debug('Invalid assertion, %s, for client %r.',
                      request.assertion, request.client)
            raise errors.InvalidGrantError('Invalid assertion.',
                                           request=request)

        original_scopes = utils.scope_to_list(
            self.request_validator.get_original_scopes(request.assertion,
                                                       request))

        if request.scope:
            request.scopes = utils.scope_to_list(request.scope)
            if (not all((s in original_scopes for s in request.scopes))
                    and not self.request_validator.is_within_original_scope(
                        request.scopes, request.refresh_token, request)):
                log.debug('Refresh token %s lack requested scopes, %r.',
                          request.refresh_token, request.scopes)
                raise errors.InvalidScopeError(request=request)
        else:
            request.scopes = original_scopes
Esempio n. 5
0
    def validate_token_request(self, request):
        """
        :param request: OAuthlib request.
        :type request: oauthlib.common.Request
        """

        for validator in self.custom_validators.pre_token:
            validator(request)

        # Check if the provider and access_code are provided
        for param in ('grant_type', 'provider', 'access_token'):
            if not getattr(request, param, None):
                raise errors.InvalidRequestError(
                    'Request is missing %s parameter.' % param,
                    request=request)

        for param in ('grant_type', 'provider', 'access_token', 'scope'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(
                    description='Duplicate %s parameter.' % param,
                    request=request)

        # This error should rarely (if ever) occur if requests are routed to
        # grant type handlers based on the grant_type parameter.
        if not request.grant_type == 'external_token':
            raise errors.UnsupportedGrantTypeError(request=request)

        if not self.request_validator.external_validator(
                request.provider, request.access_token, request):
            raise errors.InvalidGrantError('Invalid token or provider',
                                           request=request)
        else:
            if not hasattr(request.client, 'client_id'):
                raise NotImplementedError('Validate user must set the '
                                          'request.client.client_id attribute '
                                          'in authenticate_client.')

        log.debug('Authorizing access to user %r.', request.user)

        self.validate_grant_type(request)

        if request.client:
            request.client_id = request.client_id or request.client.client_id
        self.validate_scopes(request)

        for validator in self.custom_validators.post_token:
            validator(request)
 def test_missing_type(self):
     uri = 'http://i.b/l?client_id=me&scope=all+of+them'
     uri += '&redirect_uri=http%3A%2F%2Fback.to%2Fme'
     self.mock_validator.validate_request = mock.MagicMock(
         side_effect=errors.InvalidRequestError())
     headers, body, status_code = self.endpoint.create_authorization_response(
         uri, scopes=['all', 'of', 'them'])
     self.assertIn('Location', headers)
     self.assertURLEqual(headers['Location'], 'http://back.to/me?error=invalid_request&error_description=Missing+response_type+parameter.')
Esempio n. 7
0
    def validate_token_request(self, request):
        """
        Same as original method (of AuthorizationCodeGrant) except for
        letting out the request_uri and request_uri validations
        :param request:
        :return:
        """
        if request.grant_type != 'authorization_code_push':
            raise errors.UnsupportedGrantTypeError(request=request)

        if request.code is None:
            raise errors.InvalidRequestError(
                description='Missing code parameter.', request=request)

        for param in ('client_id', 'grant_type'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param,
                                                 request=request)

        if self.request_validator.client_authentication_required(request):
            if not self.request_validator.authenticate_client(request):
                log.debug('Client authentication failed, %r.', request)
                raise errors.InvalidClientError(request=request)
        elif not self.request_validator.authenticate_client_id(request.client_id, request):
            log.debug('Client authentication failed, %r.', request)
            raise errors.InvalidClientError(request=request)

        if not hasattr(request.client, 'client_id'):
            raise NotImplementedError('Authenticate client must set the '
                                      'request.client.client_id attribute '
                                      'in authenticate_client.')

        self.validate_grant_type(request)

        if not self.request_validator.validate_code(request.client_id,
                                                    request.code, request.client, request):
            log.debug('Client, %r (%r), is not allowed access to scopes %r.',
                      request.client_id, request.client, request.scopes)
            raise errors.InvalidGrantError(request=request)

        for attr in ('user', 'scopes'):
            if getattr(request, attr, None) is None:
                log.debug('request.%s was not set on code validation.', attr)
    def validate_token_request(self, request):

        super(OrgResourceOwnerPasswordCredentialsGrant,
              self).validate_token_request(request)

        if not getattr(request, 'organization_id', None):
            raise errors.InvalidRequestError(
                'Request is missing organization_id parameter.',
                request=request)

        if not self.request_validator.validate_organization(
                request.organization_id, request.user, request.client,
                request):
            raise InvalidOrganizationError('Invalid Organization given.',
                                           request=request)
Esempio n. 9
0
    def validate_token_request(self, request):
        # This method's code is based on the parent method's code
        # We removed the original comments to replace with ours
        # explaining our modifications.

        # We need to set these at None by default otherwise
        # we are going to get some AttributeError later
        request._params.setdefault("backend", None)
        request._params.setdefault("client_secret", None)

        if request.grant_type != 'convert_token':
            raise errors.UnsupportedGrantTypeError(request=request)

        # We check that a token parameter is present.
        # It should contain the social token to be used with the backend
        if request.token is None:
            raise errors.InvalidRequestError(
                description='Missing token parameter.', request=request)

        # We check that a backend parameter is present.
        # It should contain the name of the social backend to be used
        if request.backend is None:
            raise errors.InvalidRequestError(
                description='Missing backend parameter.', request=request)

        if not request.client_id:
            raise errors.MissingClientIdError(request=request)

        if not self.request_validator.validate_client_id(
                request.client_id, request):
            raise errors.InvalidClientIdError(request=request)

        # Existing code to retrieve the application instance from the client id
        if self.request_validator.client_authentication_required(request):
            log.debug('Authenticating client, %r.', request)
            if not self.request_validator.authenticate_client(request):
                log.debug('Invalid client (%r), denying access.', request)
                raise errors.InvalidClientError(request=request)
        elif not self.request_validator.authenticate_client_id(
                request.client_id, request):
            log.debug('Client authentication failed, %r.', request)
            raise errors.InvalidClientError(request=request)

        # Ensure client is authorized use of this grant type
        # We chose refresh_token as a grant_type
        # as we don't want to modify all the codebase.
        # It is also the most permissive and logical grant for our needs.
        request.grant_type = "refresh_token"
        self.validate_grant_type(request)

        self.validate_scopes(request)

        # TODO: Find a better way to pass the django request object
        strategy = load_strategy(request=request.django_request)

        try:
            backend = load_backend(
                strategy, request.backend,
                reverse(NAMESPACE + ":complete", args=(request.backend, )))
        except MissingBackend:
            raise errors.InvalidRequestError(
                description='Invalid backend parameter.', request=request)

        try:
            user = backend.do_auth(access_token=request.token)
        except requests.HTTPError as e:
            raise errors.InvalidRequestError(
                description="Backend responded with HTTP{0}: {1}.".format(
                    e.response.status_code, e.response.text),
                request=request)
        except SocialAuthBaseException as e:
            raise errors.AccessDeniedError(description=str(e), request=request)

        if not user:
            raise errors.InvalidGrantError('Invalid credentials given.',
                                           request=request)

        if not user.is_active:
            raise errors.InvalidGrantError('User inactive or deleted.',
                                           request=request)

        request.user = user
        log.debug('Authorizing access to user %r.', request.user)
    def validate_token_request(self, request):
        """
        The client makes a request to the token endpoint by adding the
        following parameters using the "application/x-www-form-urlencoded"
        format per Appendix B with a character encoding of UTF-8 in the HTTP
        request entity-body:

        grant_type
                REQUIRED.  Value MUST be set to "password".

        username
                REQUIRED.  The resource owner username.

        password
                REQUIRED.  The resource owner password.

        scope
                OPTIONAL.  The scope of the access request as described by
                `Section 3.3`_.

        If the client type is confidential or the client was issued client
        credentials (or assigned other authentication requirements), the
        client MUST authenticate with the authorization server as described
        in `Section 3.2.1`_.

        The authorization server MUST:

        o  require client authentication for confidential clients or for any
            client that was issued client credentials (or with other
            authentication requirements),

        o  authenticate the client if client authentication is included, and

        o  validate the resource owner password credentials using its
            existing password validation algorithm.

        Since this access token request utilizes the resource owner's
        password, the authorization server MUST protect the endpoint against
        brute force attacks (e.g., using rate-limitation or generating
        alerts).

        .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
        .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
        """
        for param in ('grant_type', 'access_token'):
            if not getattr(request, param):
                raise errors.InvalidRequestError(
                    'Request is missing %s parameter.' % param,
                    request=request)

        for param in ('grant_type', 'access_otken', 'scope'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(
                    description='Duplicate %s parameter.' % param,
                    request=request)

        # This error should rarely (if ever) occur if requests are routed to
        # grant type handlers based on the grant_type parameter.
        if not request.grant_type == 'facebook':
            raise errors.UnsupportedGrantTypeError(request=request)

        log.debug('Validating facebook user %s.', request.access_token)
        if not self.request_validator.validate_facebook_user(
                request.access_token, request.client, request):
            raise errors.InvalidGrantError('Invalid credentials given.',
                                           request=request)
        else:
            if not hasattr(request.client, 'client_id'):
                raise NotImplementedError('Validate user must set the '
                                          'request.client.client_id attribute '
                                          'in authenticate_client.')
        log.debug('Authorizing access to user %r.', request.user)

        # Ensure client is authorized use of this grant type
        self.validate_grant_type(request)

        if request.client:
            request.client_id = request.client_id or request.client.client_id
        self.validate_scopes(request)
Esempio n. 11
0
    def validate_token_request(self, request):
        """
        :param request: OAuthlib request.
        :type request: oauthlib.common.Request
        """
        # REQUIRED. Value MUST be set to "authorization_code".
        if request.grant_type not in ('authorization_code', 'openid'):
            raise errors.UnsupportedGrantTypeError(request=request)

        for validator in self.custom_validators.pre_token:
            validator(request)

        if request.code is None:
            raise errors.InvalidRequestError(
                description='Missing code parameter.', request=request)

        for param in ('client_id', 'grant_type', 'redirect_uri'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(
                    description='Duplicate %s parameter.' % param,
                    request=request)

        if self.request_validator.client_authentication_required(request):
            # If the client type is confidential or the client was issued client
            # credentials (or assigned other authentication requirements), the
            # client MUST authenticate with the authorization server as described
            # in Section 3.2.1.
            # https://tools.ietf.org/html/rfc6749#section-3.2.1
            if not self.request_validator.authenticate_client(request):
                log.debug('Client authentication failed, %r.', request)
                raise errors.InvalidClientError(request=request)
        elif not self.request_validator.authenticate_client_id(
                request.client_id, request):
            # REQUIRED, if the client is not authenticating with the
            # authorization server as described in Section 3.2.1.
            # https://tools.ietf.org/html/rfc6749#section-3.2.1
            log.debug('Client authentication failed, %r.', request)
            raise errors.InvalidClientError(request=request)

        if not hasattr(request.client, 'client_id'):
            raise NotImplementedError('Authenticate client must set the '
                                      'request.client.client_id attribute '
                                      'in authenticate_client.')

        request.client_id = request.client_id or request.client.client_id

        # Ensure client is authorized use of this grant type
        self.validate_grant_type(request)

        # REQUIRED. The authorization code received from the
        # authorization server.
        if not self.request_validator.validate_code(
                request.client_id, request.code, request.client, request):
            log.debug('Client, %r (%r), is not allowed access to scopes %r.',
                      request.client_id, request.client, request.scopes)
            raise errors.InvalidGrantError(request=request)

        # OPTIONAL. Validate PKCE code_verifier
        challenge = self.request_validator.get_code_challenge(
            request.code, request)

        if challenge is not None:
            if request.code_verifier is None:
                raise errors.MissingCodeVerifierError(request=request)

            challenge_method = self.request_validator.get_code_challenge_method(
                request.code, request)
            if challenge_method is None:
                raise errors.InvalidGrantError(
                    request=request, description="Challenge method not found")

            if challenge_method not in self._code_challenge_methods:
                raise errors.ServerError(
                    description="code_challenge_method {} is not supported.".
                    format(challenge_method),
                    request=request)

            if not self.validate_code_challenge(challenge, challenge_method,
                                                request.code_verifier):
                log.debug('request provided a invalid code_verifier.')
                raise errors.InvalidGrantError(request=request)
        elif self.request_validator.is_pkce_required(request.client_id,
                                                     request) is True:
            if request.code_verifier is None:
                raise errors.MissingCodeVerifierError(request=request)
            raise errors.InvalidGrantError(request=request,
                                           description="Challenge not found")

        for attr in ('user', 'scopes'):
            if getattr(request, attr, None) is None:
                log.debug('request.%s was not set on code validation.', attr)

        # REQUIRED, if the "redirect_uri" parameter was included in the
        # authorization request as described in Section 4.1.1, and their
        # values MUST be identical.
        if request.redirect_uri is None:
            request.using_default_redirect_uri = True
            request.redirect_uri = self.request_validator.get_default_redirect_uri(
                request.client_id, request)
            log.debug('Using default redirect_uri %s.', request.redirect_uri)
            if not request.redirect_uri:
                raise errors.MissingRedirectURIError(request=request)
        else:
            request.using_default_redirect_uri = False
            log.debug('Using provided redirect_uri %s', request.redirect_uri)

        if not self.request_validator.confirm_redirect_uri(
                request.client_id, request.code, request.redirect_uri,
                request.client, request):
            log.debug('Redirect_uri (%r) invalid for client %r (%r).',
                      request.redirect_uri, request.client_id, request.client)
            raise errors.MismatchingRedirectURIError(request=request)

        for validator in self.custom_validators.post_token:
            validator(request)
Esempio n. 12
0
    def validate_token_request(self, request):
        """validate token request by request attributes and jwt claims."""
        # pylint: disable-msg=too-many-branches

        # REQUIRED. Per http://tools.ietf.org/html/rfc7523#section-2.1, value
        # MUST be set to "urn:ietf:params:oauth:grant-type:jwt-bearer".
        # Note: support for receiving client authentication jwt requests
        # following the parameter values specified by rfc7523 section 2.2 is
        # not yet implemented https://tools.ietf.org/html/rfc7523#section-2.2
        if request.grant_type != 'urn:ietf:params:oauth:grant-type:jwt-bearer':
            raise errors.UnsupportedGrantTypeError(request=request)

        for validator in self.custom_validators.pre_token:
            validator(request)

        if getattr(request, 'assertion', None) is None:
            raise errors.InvalidRequestError(
                description='Missing jwt assertion parameter.',
                request=request)
        elif len(request.assertion.split(',')) > 1:
            raise errors.InvalidRequestError(
                description='Assertion MUST NOT contain more than one JWT',
                request=request)

        # Jwt MUST contain exp claim per
        # https://tools.ietf.org/html/rfc7523#section-3. Signature verification
        # is postponed for handling in request_validator after retrieval of
        # public key matching correct client.
        options = {'verify_signature': False, 'require_exp': True}

        # The JWT MUST contain an "aud" (audience) claim containing a
        # value that identifies the authorization server as an intended
        # audience.
        audience = self.request_validator.get_audience(request)
        try:
            payload = jwt.decode(request.assertion,
                                 '',
                                 audience=audience,
                                 options=options,
                                 algorithms=['RS256'])
        except jwt.ExpiredSignatureError:
            raise errors.InvalidGrantError(
                description='JWT request contains an expired signature',
                request=request)
        except jwt.ImmatureSignatureError:
            raise errors.InvalidGrantError(
                description='JWT is not yet valid (nbf)', request=request)
        except jwt.InvalidAudienceError:
            raise errors.InvalidGrantError(
                description='JWT request contains invalid audience claim',
                request=request)
        except jwt.MissingRequiredClaimError:
            raise errors.InvalidGrantError(
                description='JWT is missing a required claim', request=request)
        except jwt.DecodeError:
            raise errors.InvalidGrantError(
                description='One of more errors occurred during JWT decode',
                request=request)

        # The JWT MUST contain an "iss" (issuer) claim that contains a
        # unique identifier for the entity that issued the JWT.  In the
        # absence of an application profile specifying otherwise,
        # compliant applications MUST compare issuer values using the
        # Simple String Comparison method defined in Section 6.2.1 of RFC
        # 3986 [RFC3986] https://tools.ietf.org/html/rfc7523#section-3
        if not self.request_validator.validate_issuer(request, payload):
            msg = 'Missing or invalid (iss) claim'
            log_msg = INVALID_CLAIM.format(msg=msg, payload=payload)
            log.debug(log_msg)
            raise errors.InvalidGrantError(description=msg, request=request)

        # If client_id is not supplied as a param or claim, the issuer must be
        # client_id. client_id is validated, rather than authenticated, since
        # authentication is completed by validating token signature.
        # request.client is set in validate_client_id.
        if not request.client_id:
            request.client_id = payload.get('client_id', payload.get('iss'))
        if not self.request_validator.validate_client_id(
                request.client_id, request):
            log.debug('Client authentication failed, %s.', request)
            raise errors.InvalidClientError(request=request)

        # A validate_signature method that provides functionality for
        # retrieving the public key appropriate to the issuer or client_id,
        # and completes the decoding of the jwt using said key,
        # MUST be added to the request_validator class.
        if not self.request_validator.validate_signature(
                request, request.client, request.assertion):
            msg = 'Missing or invalid token signature'
            log_msg = INVALID_TOKEN.format(msg=msg, payload=payload)
            log.debug(log_msg)
            raise errors.InvalidGrantError(description=msg, request=request)

        # Ensure client is authorized use of this grant type.
        self.validate_grant_type(request)

        # The request_validator class must include a validate_subject method
        # that ensures the user ('sub') exists and is active.
        if not self.request_validator.validate_subject(request, request.client,
                                                       payload):
            msg = 'Missing or invalid (sub) claim'
            log_msg = INVALID_CLAIM.format(msg=msg, payload=payload)
            log.debug(log_msg)
            raise errors.InvalidGrantError(description=msg, request=request)

        # Since a jwt flow acts much like a refresh token flow, giving the
        # client access to the user's resources without the user present,
        # server's MAY wish to validate an existing authorization exists
        # containing explicit offline_access via scope or implied via
        # refresh token. A validate_offline_access method MUST be added to your
        # request_validator class; it is recommended that
        # request.refresh_tokens be set to avoid another query to validate
        # other scopes against previously authorized scopes.
        log.debug('Validating offline access for client %s.', request.client)
        if not self.request_validator.validate_offline_access(
                request, request.user, request.client):
            msg = 'Client not authorized for offline_access grants'
            log_msg = INVALID_CLAIM.format(msg=msg, payload=payload)
            log.debug(log_msg)
            raise errors.InvalidGrantError(description=msg, request=request)

        # A validate_refresh_scopes method must be implemented in the
        # request_validator class, to either verify that all requested scopes
        # are within previously authorized scopes, or allow all scopes that
        # are available to the client.
        requested_scope = request.scope or payload.get('scope')
        if not self.request_validator.validate_refresh_scopes(
                request, getattr(request, 'refresh_tokens', None),
                requested_scope):
            log.debug('Client %s lacks requested scopes, %s.',
                      request.client_id, request.scopes)
            raise errors.InvalidScopeError(request=request)

        # A jwt MAY contain additional claims. A validate_additional_claims
        # method should be implemented in the request_validator class to
        # validate all other jwt claims.
        if not self.request_validator.validate_additional_claims(
                request, payload):
            msg = ("One or more additional claims failed validation. See "
                   "provider for jwt claim requirements")
            raise errors.InvalidGrantError(description=msg, request=request)

        for validator in self.custom_validators.post_token:
            validator(request)
Esempio n. 13
0
    def validate_token_request(self, request):
        """Check the token request for normal and fatal errors.

        This method is very similar to validate_authorization_request in
        the AuthorizationCodeGrant but differ in a few subtle areas.

        A normal error could be a missing response_type parameter or the client
        attempting to access scope it is not allowed to ask authorization for.
        Normal errors can safely be included in the redirection URI and
        sent back to the client.

        Fatal errors occur when the client_id or redirect_uri is invalid or
        missing. These must be caught by the provider and handled, how this
        is done is outside of the scope of OAuthLib but showing an error
        page describing the issue is a good idea.
        """

        # First check for fatal errors

        # If the request fails due to a missing, invalid, or mismatching
        # redirection URI, or if the client identifier is missing or invalid,
        # the authorization server SHOULD inform the resource owner of the
        # error and MUST NOT automatically redirect the user-agent to the
        # invalid redirection URI.

        # REQUIRED. The client identifier as described in Section 2.2.
        # http://tools.ietf.org/html/rfc6749#section-2.2
        if not request.client_id:
            raise errors.MissingClientIdError(state=request.state,
                                              request=request)

        if not self.request_validator.validate_client_id(
                request.client_id, request):
            raise errors.InvalidClientIdError(state=request.state,
                                              request=request)

        # OPTIONAL. As described in Section 3.1.2.
        # http://tools.ietf.org/html/rfc6749#section-3.1.2
        if request.redirect_uri is not None:
            request.using_default_redirect_uri = False
            log.debug('Using provided redirect_uri %s', request.redirect_uri)
            if not is_absolute_uri(request.redirect_uri):
                raise errors.InvalidRedirectURIError(state=request.state,
                                                     request=request)

            # The authorization server MUST verify that the redirection URI
            # to which it will redirect the access token matches a
            # redirection URI registered by the client as described in
            # Section 3.1.2.
            # http://tools.ietf.org/html/rfc6749#section-3.1.2
            if not self.request_validator.validate_redirect_uri(
                    request.client_id, request.redirect_uri, request):
                raise errors.MismatchingRedirectURIError(state=request.state,
                                                         request=request)
        else:
            request.redirect_uri = self.request_validator.get_default_redirect_uri(
                request.client_id, request)
            request.using_default_redirect_uri = True
            log.debug('Using default redirect_uri %s.', request.redirect_uri)
            if not request.redirect_uri:
                raise errors.MissingRedirectURIError(state=request.state,
                                                     request=request)
            if not is_absolute_uri(request.redirect_uri):
                raise errors.InvalidRedirectURIError(state=request.state,
                                                     request=request)

        # Then check for normal errors.

        # If the resource owner denies the access request or if the request
        # fails for reasons other than a missing or invalid redirection URI,
        # the authorization server informs the client by adding the following
        # parameters to the fragment component of the redirection URI using the
        # "application/x-www-form-urlencoded" format, per Appendix B.
        # http://tools.ietf.org/html/rfc6749#appendix-B

        # Note that the correct parameters to be added are automatically
        # populated through the use of specific exceptions.
        if request.response_type is None:
            raise errors.InvalidRequestError(
                state=request.state,
                description='Missing response_type parameter.',
                request=request)

        for param in ('client_id', 'response_type', 'redirect_uri', 'scope',
                      'state'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(
                    state=request.state,
                    description='Duplicate %s parameter.' % param,
                    request=request)

        # REQUIRED. Value MUST be set to "token".
        if request.response_type not in self.VALID_RESPONSE_TYPES:
            raise errors.UnsupportedResponseTypeError(state=request.state,
                                                      request=request)

        log.debug('Validating use of response_type token for client %r (%r).',
                  request.client_id, request.client)
        if not self.request_validator.validate_response_type(
                request.client_id, request.response_type, request.client,
                request):
            log.debug('Client %s is not authorized to use response_type %s.',
                      request.client_id, request.response_type)
            raise errors.UnauthorizedClientError(request=request)

        # OPTIONAL. The scope of the access request as described by Section 3.3
        # http://tools.ietf.org/html/rfc6749#section-3.3
        self.validate_scopes(request)

        return request.scopes, {
            'client_id': request.client_id,
            'redirect_uri': request.redirect_uri,
            'response_type': request.response_type,
            'state': request.state,
            'request': request,
        }