providers/oauth2: Make AuthorizeError's state parameter requireed

This commit is contained in:
Jens Langhammer 2020-12-27 15:32:22 +01:00
parent e8debce9c8
commit e7c96eb70d
2 changed files with 19 additions and 15 deletions

View File

@ -1,5 +1,4 @@
"""OAuth errors""" """OAuth errors"""
from typing import Optional
from urllib.parse import quote from urllib.parse import quote
from authentik.lib.sentry import SentryIgnoredException from authentik.lib.sentry import SentryIgnoredException
@ -105,7 +104,7 @@ class AuthorizeError(OAuth2Error):
redirect_uri: str, redirect_uri: str,
error: str, error: str,
grant_type: str, grant_type: str,
state: Optional[str] = None, state: str,
): ):
super().__init__() super().__init__()
self.error = error self.error = error
@ -114,7 +113,7 @@ class AuthorizeError(OAuth2Error):
self.grant_type = grant_type self.grant_type = grant_type
self.state = state self.state = state
def create_uri(self, redirect_uri: str) -> str: def create_uri(self) -> str:
"""Get a redirect URI with the error message""" """Get a redirect URI with the error message"""
description = quote(str(self.description)) description = quote(str(self.description))
@ -123,7 +122,7 @@ class AuthorizeError(OAuth2Error):
hash_or_question = "#" if self.grant_type == GrantTypes.IMPLICIT else "?" hash_or_question = "#" if self.grant_type == GrantTypes.IMPLICIT else "?"
uri = "{0}{1}error={2}&error_description={3}".format( uri = "{0}{1}error={2}&error_description={3}".format(
redirect_uri, hash_or_question, self.error, description self.redirect_uri, hash_or_question, self.error, description
) )
# Add state if present. # Add state if present.

View File

@ -177,11 +177,15 @@ class OAuthAuthorizationParams:
in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN] in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN]
): ):
LOGGER.warning("Missing 'openid' scope.") LOGGER.warning("Missing 'openid' scope.")
raise AuthorizeError(self.redirect_uri, "invalid_scope", self.grant_type) raise AuthorizeError(
self.redirect_uri, "invalid_scope", self.grant_type, self.state
)
# Nonce parameter validation. # Nonce parameter validation.
if is_open_id and self.grant_type == GrantTypes.IMPLICIT and not self.nonce: if is_open_id and self.grant_type == GrantTypes.IMPLICIT and not self.nonce:
raise AuthorizeError(self.redirect_uri, "invalid_request", self.grant_type) raise AuthorizeError(
self.redirect_uri, "invalid_request", self.grant_type, self.state
)
# Response type parameter validation. # Response type parameter validation.
if is_open_id: if is_open_id:
@ -191,14 +195,14 @@ class OAuthAuthorizationParams:
actual_response_type = actual_response_type[:hash_index] actual_response_type = actual_response_type[:hash_index]
if self.response_type != actual_response_type: if self.response_type != actual_response_type:
raise AuthorizeError( raise AuthorizeError(
self.redirect_uri, "invalid_request", self.grant_type self.redirect_uri, "invalid_request", self.grant_type, self.state
) )
# PKCE validation of the transformation method. # PKCE validation of the transformation method.
if self.code_challenge: if self.code_challenge:
if not (self.code_challenge_method in ["plain", "S256"]): if not (self.code_challenge_method in ["plain", "S256"]):
raise AuthorizeError( raise AuthorizeError(
self.redirect_uri, "invalid_request", self.grant_type self.redirect_uri, "invalid_request", self.grant_type, self.state
) )
def create_code(self, request: HttpRequest) -> AuthorizationCode: def create_code(self, request: HttpRequest) -> AuthorizationCode:
@ -244,6 +248,7 @@ class OAuthFulfillmentStage(StageView):
self.params.redirect_uri, self.params.redirect_uri,
"consent_required", "consent_required",
self.params.grant_type, self.params.grant_type,
self.params.state,
) )
Event.new( Event.new(
EventAction.AUTHORIZE_APPLICATION, EventAction.AUTHORIZE_APPLICATION,
@ -257,8 +262,7 @@ class OAuthFulfillmentStage(StageView):
return bad_request_message(request, error.description, title=error.error) return bad_request_message(request, error.description, title=error.error)
except AuthorizeError as error: except AuthorizeError as error:
self.executor.stage_invalid() self.executor.stage_invalid()
uri = error.create_uri(self.params.redirect_uri) return redirect(error.create_uri())
return redirect(uri)
def create_response_uri(self) -> str: def create_response_uri(self) -> str:
"""Create a final Response URI the user is redirected to.""" """Create a final Response URI the user is redirected to."""
@ -361,7 +365,7 @@ class AuthorizationFlowInitView(PolicyAccessView):
try: try:
self.params = OAuthAuthorizationParams.from_request(self.request) self.params = OAuthAuthorizationParams.from_request(self.request)
except AuthorizeError as error: except AuthorizeError as error:
raise RequestValidationError(redirect(error.create_uri(error.redirect_uri))) raise RequestValidationError(redirect(error.create_uri()))
except OAuth2Error as error: except OAuth2Error as error:
raise RequestValidationError( raise RequestValidationError(
bad_request_message(self.request, error.description, title=error.error) bad_request_message(self.request, error.description, title=error.error)
@ -371,11 +375,12 @@ class AuthorizationFlowInitView(PolicyAccessView):
if PROMPT_NONE in self.params.prompt and not self.request.user.is_authenticated: if PROMPT_NONE in self.params.prompt and not self.request.user.is_authenticated:
# When "prompt" is set to "none" but the user is not logged in, show an error message # When "prompt" is set to "none" but the user is not logged in, show an error message
error = AuthorizeError( error = AuthorizeError(
self.params.redirect_uri, "login_required", self.params.grant_type self.params.redirect_uri,
) "login_required",
raise RequestValidationError( self.params.grant_type,
redirect(error.create_uri(self.params.redirect_uri)) self.params.state,
) )
raise RequestValidationError(redirect(error.create_uri()))
def resolve_provider_application(self): def resolve_provider_application(self):
client_id = self.request.GET.get("client_id") client_id = self.request.GET.get("client_id")