def _handle_redirects(self, request): 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(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. # https://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(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(request=request) if not is_absolute_uri(request.redirect_uri): raise errors.InvalidRedirectURIError(request=request)
def default_redirect_uri(self): """ Returns the default redirect_uri, *if* only one is registered. """ if self.redirect_uris: uris = self.redirect_uris.split() if len(uris) == 1: return self.redirect_uris.split().pop(0) raise errors.MissingRedirectURIError() assert False, ("If you are using implicit, authorization_code " "or all-in-one grant_type, you must define " "redirect_uris field in your Application model")
def validate_redirect_uri(self, request): if not request.redirect_uri: request.redirect_uri = self.request_validator.get_default_redirect_uri( request.client_id, request) 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) if not self.request_validator.validate_redirect_uri( request.client_id, request.redirect_uri, request): raise errors.MismatchingRedirectURIError(state=request.state, request=request)
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)
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, }