From 2d2a4040281c8a320af93249d10744becfc171b1 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 16 Jan 2021 18:27:10 +0100 Subject: [PATCH] providers/oauth2: improve error handling and event creation --- authentik/providers/oauth2/errors.py | 36 +++++++++++++++++-- authentik/providers/oauth2/views/authorize.py | 21 ++++++----- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/authentik/providers/oauth2/errors.py b/authentik/providers/oauth2/errors.py index 70cf96dd1..89f2416f0 100644 --- a/authentik/providers/oauth2/errors.py +++ b/authentik/providers/oauth2/errors.py @@ -1,6 +1,8 @@ """OAuth errors""" +from typing import Optional from urllib.parse import quote +from authentik.events.models import Event, EventAction from authentik.lib.sentry import SentryIgnoredException from authentik.providers.oauth2.models import GrantTypes @@ -21,6 +23,13 @@ class OAuth2Error(SentryIgnoredException): def __repr__(self) -> str: return self.error + def to_event(self, message: Optional[str] = None) -> Event: + """Create configuration_error Event and save it.""" + return Event.new( + EventAction.CONFIGURATION_ERROR, + message=message or self.description, + ) + class RedirectUriError(OAuth2Error): """The request fails due to a missing, invalid, or mismatching @@ -28,10 +37,24 @@ class RedirectUriError(OAuth2Error): error = "Redirect URI Error" description = ( - "The request fails due to a missing, invalid, or mismatching" - " redirection URI (redirect_uri)." + "The request fails due to a missing, invalid, or mismatching " + "redirection URI (redirect_uri)." ) + provided_uri: str + allowed_uris: list[str] + + def __init__(self, provided_uri: str, allowed_uris: list[str]) -> None: + super().__init__() + self.provided_uri = provided_uri + self.allowed_uris = allowed_uris + + def to_event(self) -> Event: + return super().to_event( + f"Invalid redirect URI was used. Client used '{self.provided_uri}'. " + f"Allowed redirect URIs are {','.join(self.allowed_uris)}" + ) + class ClientIdError(OAuth2Error): """The client identifier (client_id) is missing or invalid.""" @@ -39,6 +62,15 @@ class ClientIdError(OAuth2Error): error = "Client ID Error" description = "The client identifier (client_id) is missing or invalid." + client_id: str + + def __init__(self, client_id: str) -> None: + super().__init__() + self.client_id = client_id + + def to_event(self) -> Event: + return super().to_event(f"Invalid client identifier: {self.client_id}.") + class UserAuthError(OAuth2Error): """ diff --git a/authentik/providers/oauth2/views/authorize.py b/authentik/providers/oauth2/views/authorize.py index 7be40f599..36106ddf7 100644 --- a/authentik/providers/oauth2/views/authorize.py +++ b/authentik/providers/oauth2/views/authorize.py @@ -145,7 +145,7 @@ class OAuthAuthorizationParams: ) except OAuth2Provider.DoesNotExist: LOGGER.warning("Invalid client identifier", client_id=self.client_id) - raise ClientIdError() + raise ClientIdError(client_id=self.client_id) self.check_redirect_uri() self.check_scope() self.check_nonce() @@ -155,24 +155,18 @@ class OAuthAuthorizationParams: """Redirect URI validation.""" if not self.redirect_uri: LOGGER.warning("Missing redirect uri.") - raise RedirectUriError() + raise RedirectUriError("", self.provider.redirect_uris.split()) if self.redirect_uri.lower() not in [ x.lower() for x in self.provider.redirect_uris.split() ]: - Event.new( - EventAction.CONFIGURATION_ERROR, - provider=self.provider, - message="Invalid redirect URI was used.", - client_used=self.redirect_uri, - configured=self.provider.redirect_uris.split(), - ).save() LOGGER.warning( "Invalid redirect uri", redirect_uri=self.redirect_uri, excepted=self.provider.redirect_uris.split(), ) - raise RedirectUriError() - + raise RedirectUriError( + self.redirect_uri, self.provider.redirect_uris.split() + ) if self.request: raise AuthorizeError( self.redirect_uri, "request_not_supported", self.grant_type, self.state @@ -262,10 +256,12 @@ class OAuthFulfillmentStage(StageView): ).from_http(self.request) return redirect(self.create_response_uri()) except (ClientIdError, RedirectUriError) as error: + error.to_event().from_http(request) self.executor.stage_invalid() # pylint: disable=no-member return bad_request_message(request, error.description, title=error.error) except AuthorizeError as error: + error.to_event().from_http(request) self.executor.stage_invalid() return redirect(error.create_uri()) @@ -383,8 +379,10 @@ class AuthorizationFlowInitView(PolicyAccessView): try: self.params = OAuthAuthorizationParams.from_request(self.request) except AuthorizeError as error: + error.to_event().from_http(self.request) raise RequestValidationError(redirect(error.create_uri())) except OAuth2Error as error: + error.to_event().from_http(self.request) raise RequestValidationError( bad_request_message(self.request, error.description, title=error.error) ) @@ -398,6 +396,7 @@ class AuthorizationFlowInitView(PolicyAccessView): self.params.grant_type, self.params.state, ) + error.to_event().from_http(self.request) raise RequestValidationError(redirect(error.create_uri())) def resolve_provider_application(self):