providers/oauth2: Make AuthorizeError's state parameter requireed
This commit is contained in:
parent
e8debce9c8
commit
e7c96eb70d
|
@ -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.
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Reference in New Issue