Skip to content

Commit

Permalink
tighten login csrf protection by using a login timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
lilioid committed Dec 27, 2024
1 parent 43dfc57 commit ed3abbb
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/simple_openid_connect/integrations/django/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class SettingsModel(BaseModel):
)
"A string specifying a class that inherits from :class:`simple_openid_connect.integrations.django.user_mapping.UserMapper`."

OPENID_LOGIN_TIMEOUT: int = 60 * 5
"Time in seconds which a login procedure is allowed to take at maximum. If a user takes more than this time between initiating a login and completing it, the login process fails and they have to redo it."


class OpenidAppConfig(AppConfig):
"""
Expand Down
11 changes: 8 additions & 3 deletions src/simple_openid_connect/integrations/django/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import logging
import secrets
from datetime import UTC, datetime, timedelta
from http import HTTPStatus
from typing import Mapping

Expand Down Expand Up @@ -69,7 +70,7 @@ def get(self, request: HttpRequest) -> HttpResponse:

# save the login state into the session to prevent CSRF attacks (openid state parameter could be used instead)
# See https://www.rfc-editor.org/rfc/rfc6749#section-10.12
request.session["openid_auth_in_progress"] = True
request.session["openid_auth_start_time"] = datetime.now(tz=UTC).timestamp()

# prevent replay attacks by generating and specifying a nonce
nonce = secrets.token_urlsafe(48)
Expand All @@ -93,13 +94,17 @@ class LoginCallbackView(View):
"""

def get(self, request: HttpRequest) -> HttpResponse:
app_settings = OpenidAppConfig.get_instance().safe_settings
client = OpenidAppConfig.get_instance().get_client(request)

# prevent CSRF attacks by verifying that the user agent is curently in the process of authenticating
if request.session.get("openid_auth_in_progress", False) is not True:
if request.session.get("openid_auth_start_time", None) is None or (
datetime.now(tz=UTC)
- datetime.fromtimestamp(request.session["openid_auth_start_time"], tz=UTC)
) > timedelta(seconds=app_settings.OPENID_LOGIN_TIMEOUT):
raise InvalidAuthStateError()
else:
del request.session["openid_auth_in_progress"]
del request.session["openid_auth_start_time"]

# exchange the passed code for tokens
token_response = client.authorization_code_flow.handle_authentication_result(
Expand Down

0 comments on commit ed3abbb

Please sign in to comment.