Exemple #1
0
 def validate_scopes(self, request):
     if not request.scopes:
         request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list(
                 self.request_validator.get_default_scopes(request.client_id, request))
     log.debug('Validating access to scopes %r for client %r (%r).',
               request.scopes, request.client_id, request.client)
     if not self.request_validator.validate_scopes(request.client_id,
             request.scopes, request.client, request):
         raise errors.InvalidScopeError(state=request.state, request=request)
 def validate_scopes(self, request):
     """
     :param request: OAuthlib request.
     :type request: oauthlib.common.Request
     """
     if not request.scopes:
         request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list(
             self.request_validator.get_default_scopes(request.client_id, request))
     log.debug('Validating access to scopes %r for client %r (%r).',
               request.scopes, request.client_id, request.client)
     if not self.request_validator.validate_scopes(request.client_id,
                                                   request.scopes, request.client, request):
         raise errors.InvalidScopeError(request=request)
Exemple #3
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
Exemple #4
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)