Skip to content

Commit

Permalink
🏷️ [#83] Add some more type annotations
Browse files Browse the repository at this point in the history
Making it easier to reason about the code and check attributes
of provided config classes.
  • Loading branch information
sergei-maertens committed Feb 6, 2024
1 parent b589bfe commit 050d8bc
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 20 deletions.
29 changes: 17 additions & 12 deletions mozilla_django_oidc_db/backends.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fnmatch
import logging
from typing import Any, Dict
from typing import Any, Dict, Generic, List, TypeVar, cast

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
Expand All @@ -12,14 +12,16 @@
)

from .mixins import GetAttributeMixin, SoloConfigMixin
from .models import UserInformationClaimsSources
from .models import OpenIDConnectConfig, UserInformationClaimsSources
from .utils import obfuscate_claims

logger = logging.getLogger(__name__)

T = TypeVar("T", bound=OpenIDConnectConfig)


class OIDCAuthenticationBackend(
GetAttributeMixin, SoloConfigMixin, _OIDCAuthenticationBackend
GetAttributeMixin, SoloConfigMixin[T], _OIDCAuthenticationBackend, Generic[T]
):
"""
Modifies the default OIDCAuthenticationBackend to use a configurable claim
Expand Down Expand Up @@ -159,15 +161,18 @@ def update_user_superuser_status(self, user, claims):
no longer member of at least one of these groups.
"""
groups_claim = self.config.groups_claim
superuser_group_names = self.config.superuser_group_names

if superuser_group_names:
claim_groups = glom(claims, groups_claim, default=[])
if set(superuser_group_names) & set(claim_groups):
user.is_superuser = True
else:
user.is_superuser = False
user.save()
# can't do an isinstance check here
superuser_group_names = cast(List[str], self.config.superuser_group_names)

if not superuser_group_names:
return

claim_groups = glom(claims, groups_claim, default=[])
if set(superuser_group_names) & set(claim_groups):
user.is_superuser = True
else:
user.is_superuser = False
user.save()

def update_user_groups(self, user, claims):
"""
Expand Down
22 changes: 15 additions & 7 deletions mozilla_django_oidc_db/mixins.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
from typing import Generic, Type, TypeVar, cast

from mozilla_django_oidc.utils import import_from_settings

from .models import OpenIDConnectConfig
from .models import OpenIDConnectConfig, OpenIDConnectConfigBase

T = TypeVar("T", bound=OpenIDConnectConfigBase)


class SoloConfigMixin:
config_class = OpenIDConnectConfig
class SoloConfigMixin(Generic[T]):
config_class: Type[OpenIDConnectConfig] = OpenIDConnectConfig
_solo_config: T

@property
def config(self):
def config(self) -> T:
if not hasattr(self, "_solo_config"):
self._solo_config = self.config_class.get_solo()
config = self.config_class.get_solo()
self._solo_config = cast(
T, config
) # django-solo and type checking is challenging
return self._solo_config

def refresh_config(self):
def refresh_config(self) -> None:
"""
Refreshes the cached config on the instance, required for middleware
since middleware is only instantiated once (during the Django startup phase)
Expand All @@ -34,7 +42,7 @@ def get_settings(self, attr, *args):


class GetAttributeMixin:
def __getattribute__(self, attr):
def __getattribute__(self, attr: str):
"""
Mixin used to avoid calls to the config model on __init__ and instead
do these calls runtime
Expand Down
1 change: 1 addition & 0 deletions mozilla_django_oidc_db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class OpenIDConnectConfigBase(SingletonModel):
max_length=1000,
help_text=_("URL of your OpenID Connect provider userinfo endpoint"),
)

oidc_rp_idp_sign_key = models.CharField(
_("Sign key"),
max_length=1000,
Expand Down
Empty file added mozilla_django_oidc_db/py.typed
Empty file.
Empty file.
23 changes: 22 additions & 1 deletion tests/test_integration_oidc_flow_variants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import pytest

from mozilla_django_oidc_db.models import OpenIDConnectConfig
from mozilla_django_oidc_db.models import (
OpenIDConnectConfig,
UserInformationClaimsSources,
)

from .utils import keycloak_login

Expand Down Expand Up @@ -78,3 +81,21 @@ def test_credentials_in_basic_auth_header(

assert b"client_id=testid" in token_request.body
assert b"secret=" not in token_request.body


# @pytest.mark.vcr
# def test_return_jwt_from_userinfo_endpoint(
# keycloak_config: OpenIDConnectConfig,
# mock_state_and_nonce,
# client,
# django_user_model,
# vcr,
# ):
# keycloak_config.userinfo_claims_source = (
# UserInformationClaimsSources.userinfo_endpoint
# )
# keycloak_config.save()

# django_login_response = client.get(reverse("login"))
# # simulate login to Keycloak
# redirect_uri = keycloak_login(django_login_response["Location"])

0 comments on commit 050d8bc

Please sign in to comment.