Skip to content

Commit

Permalink
🐛 Fix SessionRefresh flow for new architecture
Browse files Browse the repository at this point in the history
previously, the callback view never had access to the config class, because this is deleted after successful login by mozilla-django-oidc, causing the callbackview to crash
  • Loading branch information
stevenbal committed Jul 1, 2024
1 parent 428e8c0 commit f6f9e2c
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 6 deletions.
1 change: 1 addition & 0 deletions mozilla_django_oidc_db/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ class MozillaDjangoOidcDbConfig(AppConfig):

def ready(self) -> None:
from . import checks # noqa
from . import signals # noqa
10 changes: 9 additions & 1 deletion mozilla_django_oidc_db/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,15 @@ def authenticate( # type: ignore
return None

# Allright, now try to actually authenticate the user.
return super().authenticate(request, nonce=nonce, code_verifier=code_verifier)
user = super().authenticate(request, nonce=nonce, code_verifier=code_verifier)

# Store the config class name on the user, so that we can store this in the user's
# session after they have been successfully authenticated (by listening to the `user_logged_in` signal)
if user:
options = self.config_class._meta
user._oidcdb_config_class = f"{options.app_label}.{options.object_name}" # type: ignore

return user

def _extract_username(
self, claims: JSONObject, *, raise_on_empty: bool = False
Expand Down
17 changes: 12 additions & 5 deletions mozilla_django_oidc_db/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from mozilla_django_oidc.utils import import_from_settings
from typing_extensions import Self, TypedDict, Unpack

from .constants import CONFIG_CLASS_SESSION_KEY
from .models import OpenIDConnectConfigBase


Expand Down Expand Up @@ -109,19 +110,25 @@ def store_config(request: HttpRequest) -> None:
mozilla-django-oidc's callback view deletes the state key after it has validated it,
so our :func:`lookup_config` cannot extract it from the session anymore.
"""
# Attempt to retrieve the config_class from the session, this only works for users
# that are actually logged in as Django users
# The config_class key is added to the state in the OIDCInit.get method.
# TODO: verify that the state query param is present for error flows! Need to check
# the OAUTH2 spec for this, but according to ChatGeePeeTee if the request contains
# it, the callback must have it too.
config_class = ""
state_key = request.GET.get("state")
if not state_key or state_key not in (
states := request.session.get("oidc_states", [])
if state_key and state_key in (states := request.session.get("oidc_states", [])):
state = states[state_key]
config_class = state.get("config_class", "")

if not config_class and (
_config := request.session.get(CONFIG_CLASS_SESSION_KEY, "")
):
raise BadRequest("Could not look up the referenced config.")
config_class = _config

state = states[state_key]
try:
config = apps.get_model(state.get("config_class", ""))
config = apps.get_model(config_class)
except (LookupError, ValueError) as exc:
raise BadRequest("Could not look up the referenced config.") from exc

Expand Down
2 changes: 2 additions & 0 deletions mozilla_django_oidc_db/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
}

OPEN_ID_CONFIG_PATH = ".well-known/openid-configuration"

CONFIG_CLASS_SESSION_KEY = "_OIDCDB_CONFIG_CLASS"
14 changes: 14 additions & 0 deletions mozilla_django_oidc_db/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver

from .constants import CONFIG_CLASS_SESSION_KEY


@receiver([user_logged_in], dispatch_uid="oidcdb.set_config_class")
def set_oidcdb_config_class_on_session(sender, user, request, **kwargs):
"""
Record the OIDC config class on the session, this is needed so the callback view
can retrieve the config in case of a SessionRefresh flow
"""
if hasattr(user, "_oidcdb_config_class"):
request.session[CONFIG_CLASS_SESSION_KEY] = user._oidcdb_config_class

0 comments on commit f6f9e2c

Please sign in to comment.