Skip to content

Commit

Permalink
Merge pull request #28 from timhallmann/add_state_nonce_prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
lilioid authored Oct 15, 2024
2 parents 76ae516 + cdef762 commit 29b56c3
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
TokenRequest,
TokenSuccessResponse,
)
from simple_openid_connect.exceptions import AuthenticationFailedError
from simple_openid_connect.exceptions import AuthenticationFailedError, ValidationError

logger = logging.getLogger(__name__)

Expand All @@ -31,20 +31,31 @@ def start_authentication(
scope: str,
client_id: str,
redirect_uri: str,
state: Optional[str] = None,
nonce: Optional[str] = None,
prompt: Optional[list[str]] = None,
code_challenge: Optional[str] = None,
code_challenge_method: Optional[str] = None,
) -> str:
"""
Start the authentication process by constructing an appropriate :class:`AuthenticationRequest`, serializing it and
returning a which the end user now needs to visit.
:param state: The state intended to prevent Cross-Site Request Forgery.
:param nonce: String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
:param prompt: Specifies whether the Authorization Server prompts the End-User for reauthentication and consent.
The defined values are: "none", "login", "consent" and "select_account", multiple may be given as a list.
:returns: A URL to which the user agent should be redirected
"""
request = AuthenticationRequest(
scope=scope,
client_id=client_id,
redirect_uri=redirect_uri,
response_type="code",
state=state,
nonce=nonce,
prompt=prompt,
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
)
Expand All @@ -56,6 +67,7 @@ def handle_authentication_result(
token_endpoint: str,
client_authentication: ClientAuthenticationMethod,
redirect_uri: Union[Literal["auto"], str] = "auto",
state: Optional[str] = None,
code_verifier: Optional[str] = None,
code_challenge: Optional[str] = None,
code_challenge_method: Optional[str] = None,
Expand All @@ -70,8 +82,10 @@ def handle_authentication_result(
:param client_authentication: A way for the client to authenticate itself
:param redirect_uri: The `redirect_uri` that was specified during the authentication initiation.
If the special value `auto` is used, it is assumed that `current_url` is the that callback and it is stripped of query parameters and fragments to reproduce the originally supplied one.
:param state: The `state` that was specified during the authentication initiation.
:raises AuthenticationFailedError: If the current url indicates an authentication failure that prevents an access token from being retrieved.
:raises ValidationError: If the returned state does not match the given state.
:returns: The result of the token exchange
"""
Expand All @@ -92,6 +106,10 @@ def handle_authentication_result(
)

auth_response_msg = AuthenticationSuccessResponse.parse_url(str(current_furl))

if state != auth_response_msg.state:
raise ValidationError("Returned state does not match given state.")

return exchange_code_for_tokens(
token_endpoint=token_endpoint,
authentication_response=auth_response_msg,
Expand Down
13 changes: 13 additions & 0 deletions src/simple_openid_connect/flows/authorization_code_flow/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ def __init__(self, base_client: "OpenidClient"):

def start_authentication(
self,
state: Optional[str] = None,
nonce: Optional[str] = None,
prompt: Optional[list[str]] = None,
code_challenge: Optional[str] = None,
code_challenge_method: Optional[str] = None,
) -> str:
"""
Start the authentication process by constructing an appropriate :class:`AuthenticationRequest`, serializing it and
returning a which the end user now needs to visit.
:param state: The state intended to prevent Cross-Site Request Forgery.
:param nonce: String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
:param prompt: Specifies whether the Authorization Server prompts the End-User for reauthentication and consent.
The defined values are: "none", "login", "consent" and "select_account", multiple may be given as a list.
:param code_challenge: The code challenge intended for use with Proof Key for Code Exchange (PKCE) [RFC7636].
:param code_challenge_method: The code challenge method intended for use with Proof Key for Code Exchange (PKCE) [RFC7636], typically "S256" or "plain".
Expand All @@ -55,6 +62,9 @@ def start_authentication(
self._base_client.scope,
self._base_client.client_auth.client_id,
redirect_uri.tostr(),
state=state,
nonce=nonce,
prompt=prompt,
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
)
Expand All @@ -63,6 +73,7 @@ def handle_authentication_result(
self,
current_url: str,
additional_redirect_args: Optional[Mapping[str, str]] = None,
state: Optional[str] = None,
code_verifier: Optional[str] = None,
code_challenge: Optional[str] = None,
code_challenge_method: Optional[str] = None,
Expand All @@ -74,6 +85,7 @@ def handle_authentication_result(
The authentication result should be encoded into this url by the authorization server.
:param additional_redirect_args: Additional URL parameters that were added to the redirect uri.
They are probably still present in `current_url` but since they could be of any shape, no attempt is made here to automatically reconstruct them.
:param state: The `state` that was specified during the authentication initiation.
:param code_verifier: The code verifier intended for use with Proof Key for Code Exchange (PKCE) [RFC7636].
:param code_challenge: The code challenge intended for use with Proof Key for Code Exchange (PKCE) [RFC7636].
:param code_challenge_method: The code challenge method intended for use with Proof Key for Code Exchange (PKCE) [RFC7636], typically "S256" or "plain".
Expand Down Expand Up @@ -103,6 +115,7 @@ def handle_authentication_result(
token_endpoint=self._base_client.provider_config.token_endpoint,
client_authentication=self._base_client.client_auth,
redirect_uri=redirect_uri.tostr(),
state=state,
code_verifier=code_verifier,
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
Expand Down

0 comments on commit 29b56c3

Please sign in to comment.