From 0bedd5c093737047f4f42227084c25d110b127c7 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 28 May 2024 11:03:55 +0200 Subject: [PATCH] :truck: Split models into separate modules Organizing by DigiD and eHerkenning, similarly to the SAML models. --- digid_eherkenning/oidc/forms.py | 2 +- digid_eherkenning/oidc/models.py | 213 ------------------- digid_eherkenning/oidc/models/__init__.py | 12 ++ digid_eherkenning/oidc/models/base.py | 31 +++ digid_eherkenning/oidc/models/digid.py | 83 ++++++++ digid_eherkenning/oidc/models/eherkenning.py | 88 ++++++++ 6 files changed, 215 insertions(+), 214 deletions(-) delete mode 100644 digid_eherkenning/oidc/models.py create mode 100644 digid_eherkenning/oidc/models/__init__.py create mode 100644 digid_eherkenning/oidc/models/base.py create mode 100644 digid_eherkenning/oidc/models/digid.py create mode 100644 digid_eherkenning/oidc/models/eherkenning.py diff --git a/digid_eherkenning/oidc/forms.py b/digid_eherkenning/oidc/forms.py index aeed63d..2aa32f1 100644 --- a/digid_eherkenning/oidc/forms.py +++ b/digid_eherkenning/oidc/forms.py @@ -5,7 +5,7 @@ from mozilla_django_oidc_db.constants import OIDC_MAPPING from mozilla_django_oidc_db.forms import OpenIDConnectConfigForm -from .models import OpenIDConnectBaseConfig +from .models.base import OpenIDConnectBaseConfig def admin_modelform_factory(model: type[OpenIDConnectBaseConfig], *args, **kwargs): diff --git a/digid_eherkenning/oidc/models.py b/digid_eherkenning/oidc/models.py deleted file mode 100644 index d4326f4..0000000 --- a/digid_eherkenning/oidc/models.py +++ /dev/null @@ -1,213 +0,0 @@ -from collections.abc import Collection -from typing import ClassVar - -from django.db import models -from django.utils.functional import classproperty -from django.utils.translation import gettext_lazy as _ - -from django_jsonform.models.fields import ArrayField -from mozilla_django_oidc_db.models import OpenIDConnectConfigBase -from mozilla_django_oidc_db.typing import ClaimPath - - -def get_default_scopes_bsn(): - """ - Returns the default scopes to request for OpenID Connect logins - """ - return ["openid", "bsn"] - - -def get_default_scopes_kvk(): - """ - Returns the default scopes to request for OpenID Connect logins - """ - return ["openid", "kvk"] - - -class OpenIDConnectBaseConfig(OpenIDConnectConfigBase): - """ - Configuration for DigiD authentication via OpenID connect - """ - - oidc_op_logout_endpoint = models.URLField( - _("Logout endpoint"), - max_length=1000, - help_text=_("URL of your OpenID Connect provider logout endpoint"), - blank=True, - ) - - # Keycloak specific config - oidc_keycloak_idp_hint = models.CharField( - _("Keycloak Identity Provider hint"), - max_length=1000, - help_text=_( - "Specific for Keycloak: parameter that indicates which identity provider " - "should be used (therefore skipping the Keycloak login screen)." - ), - blank=True, - ) - - class Meta: - verbose_name = _("OpenID Connect configuration") - abstract = True - - @classproperty - def oidcdb_check_idp_availability(cls) -> bool: - return True - - -class DigiDConfig(OpenIDConnectBaseConfig): - """ - Configuration for DigiD authentication via OpenID connect - """ - - identifier_claim_name = models.CharField( - _("BSN claim name"), - max_length=100, - help_text=_("The name of the claim in which the BSN of the user is stored"), - default="bsn", - ) - oidc_rp_scopes_list = ArrayField( - verbose_name=_("OpenID Connect scopes"), - base_field=models.CharField(_("OpenID Connect scope"), max_length=50), - default=get_default_scopes_bsn, - blank=True, - help_text=_( - "OpenID Connect scopes that are requested during login. " - "These scopes are hardcoded and must be supported by the identity provider" - ), - ) - - custom_oidc_db_prefix: ClassVar[str] = "digid_oidc" - - class Meta: - verbose_name = _("OpenID Connect configuration for DigiD") - - @property - def oidcdb_username_claim(self) -> list[str]: - return [self.identifier_claim_name] - - -class DigiDMachtigenConfig(OpenIDConnectBaseConfig): - # TODO: support periods in claim keys - vertegenwoordigde_claim_name = models.CharField( - verbose_name=_("vertegenwoordigde claim name"), - default="aanvrager.bsn", - max_length=50, - help_text=_( - "Name of the claim in which the BSN of the person being represented is stored" - ), - ) - gemachtigde_claim_name = models.CharField( - verbose_name=_("gemachtigde claim name"), - default="gemachtigde.bsn", - max_length=50, - help_text=_( - "Name of the claim in which the BSN of the person representing someone else is stored" - ), - ) - oidc_rp_scopes_list = ArrayField( - verbose_name=_("OpenID Connect scopes"), - base_field=models.CharField(_("OpenID Connect scope"), max_length=50), - default=get_default_scopes_bsn, - blank=True, - help_text=_( - "OpenID Connect scopes that are requested during login. " - "These scopes are hardcoded and must be supported by the identity provider" - ), - ) - - custom_oidc_db_prefix: ClassVar[str] = "digid_machtigen_oidc" - - class Meta: - verbose_name = _("OpenID Connect configuration for DigiD Machtigen") - - @property - def digid_eherkenning_machtigen_claims(self) -> dict[str, ClaimPath]: - return { - "vertegenwoordigde": [self.vertegenwoordigde_claim_name], - "gemachtigde": [self.gemachtigde_claim_name], - } - - @property - def oidcdb_sensitive_claims(self) -> Collection[ClaimPath]: - return list(self.digid_eherkenning_machtigen_claims.values()) - - -class EHerkenningConfig(OpenIDConnectBaseConfig): - """ - Configuration for eHerkenning authentication via OpenID connect - """ - - identifier_claim_name = models.CharField( - _("KVK claim name"), - max_length=100, - help_text=_("The name of the claim in which the KVK of the user is stored"), - default="kvk", - ) - oidc_rp_scopes_list = ArrayField( - verbose_name=_("OpenID Connect scopes"), - base_field=models.CharField(_("OpenID Connect scope"), max_length=50), - default=get_default_scopes_kvk, - blank=True, - help_text=_( - "OpenID Connect scopes that are requested during login. " - "These scopes are hardcoded and must be supported by the identity provider" - ), - ) - - custom_oidc_db_prefix: ClassVar[str] = "eherkenning_oidc" - - class Meta: - verbose_name = _("OpenID Connect configuration for eHerkenning") - - @property - def oidcdb_username_claim(self) -> list[str]: - return [self.identifier_claim_name] - - -class EHerkenningBewindvoeringConfig(OpenIDConnectBaseConfig): - # TODO: support periods in claim keys - vertegenwoordigde_company_claim_name = models.CharField( - verbose_name=_("vertegenwoordigde company claim name"), - default="aanvrager.kvk", - max_length=50, - help_text=_( - "Name of the claim in which the KVK of the company being represented is stored" - ), - ) - gemachtigde_person_claim_name = models.CharField( - verbose_name=_("gemachtigde person claim name"), - default="gemachtigde.pseudoID", - max_length=50, - help_text=_( - "Name of the claim in which the ID of the person representing a company is stored" - ), - ) - oidc_rp_scopes_list = ArrayField( - verbose_name=_("OpenID Connect scopes"), - base_field=models.CharField(_("OpenID Connect scope"), max_length=50), - default=get_default_scopes_bsn, - blank=True, - help_text=_( - "OpenID Connect scopes that are requested during login. " - "These scopes are hardcoded and must be supported by the identity provider" - ), - ) - - custom_oidc_db_prefix: ClassVar[str] = "eherkenning_bewindvoering_oidc" - - class Meta: - verbose_name = _("OpenID Connect configuration for eHerkenning Bewindvoering") - - @property - def digid_eherkenning_machtigen_claims(self) -> dict[str, ClaimPath]: - # TODO: this nomenclature isn't entirely correct - return { - "vertegenwoordigde": [self.vertegenwoordigde_company_claim_name], - "gemachtigde": [self.gemachtigde_person_claim_name], - } - - @property - def oidcdb_sensitive_claims(self) -> Collection[ClaimPath]: - return list(self.digid_eherkenning_machtigen_claims.values()) diff --git a/digid_eherkenning/oidc/models/__init__.py b/digid_eherkenning/oidc/models/__init__.py new file mode 100644 index 0000000..52f9b95 --- /dev/null +++ b/digid_eherkenning/oidc/models/__init__.py @@ -0,0 +1,12 @@ +from .base import get_default_scopes_bsn, get_default_scopes_kvk +from .digid import DigiDConfig, DigiDMachtigenConfig +from .eherkenning import EHerkenningBewindvoeringConfig, EHerkenningConfig + +__all__ = [ + "get_default_scopes_bsn", + "get_default_scopes_kvk", + "DigiDConfig", + "DigiDMachtigenConfig", + "EHerkenningConfig", + "EHerkenningBewindvoeringConfig", +] diff --git a/digid_eherkenning/oidc/models/base.py b/digid_eherkenning/oidc/models/base.py new file mode 100644 index 0000000..beef3cf --- /dev/null +++ b/digid_eherkenning/oidc/models/base.py @@ -0,0 +1,31 @@ +from django.utils.functional import classproperty +from django.utils.translation import gettext_lazy as _ + +from mozilla_django_oidc_db.models import OpenIDConnectConfigBase + + +def get_default_scopes_bsn(): + """ + Returns the default scopes to request for OpenID Connect logins + """ + return ["openid", "bsn"] + + +def get_default_scopes_kvk(): + """ + Returns the default scopes to request for OpenID Connect logins + """ + return ["openid", "kvk"] + + +class OpenIDConnectBaseConfig(OpenIDConnectConfigBase): + """ + Base configuration for DigiD/eHerkenning authentication via OpenID Connect. + """ + + class Meta: + abstract = True + + @classproperty + def oidcdb_check_idp_availability(cls) -> bool: + return True diff --git a/digid_eherkenning/oidc/models/digid.py b/digid_eherkenning/oidc/models/digid.py new file mode 100644 index 0000000..03b2091 --- /dev/null +++ b/digid_eherkenning/oidc/models/digid.py @@ -0,0 +1,83 @@ +from collections.abc import Collection + +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from django_jsonform.models.fields import ArrayField +from mozilla_django_oidc_db.typing import ClaimPath + +from .base import OpenIDConnectBaseConfig, get_default_scopes_bsn + + +class DigiDConfig(OpenIDConnectBaseConfig): + """ + Configuration for DigiD authentication via OpenID connect + """ + + identifier_claim_name = models.CharField( + _("BSN claim name"), + max_length=100, + help_text=_("The name of the claim in which the BSN of the user is stored"), + default="bsn", + ) + oidc_rp_scopes_list = ArrayField( + verbose_name=_("OpenID Connect scopes"), + base_field=models.CharField(_("OpenID Connect scope"), max_length=50), + default=get_default_scopes_bsn, + blank=True, + help_text=_( + "OpenID Connect scopes that are requested during login. " + "These scopes are hardcoded and must be supported by the identity provider" + ), + ) + + class Meta: + verbose_name = _("OpenID Connect configuration for DigiD") + + @property + def oidcdb_username_claim(self) -> list[str]: + return [self.identifier_claim_name] + + +class DigiDMachtigenConfig(OpenIDConnectBaseConfig): + # TODO: support periods in claim keys + vertegenwoordigde_claim_name = models.CharField( + verbose_name=_("vertegenwoordigde claim name"), + default="aanvrager.bsn", + max_length=50, + help_text=_( + "Name of the claim in which the BSN of the person being represented is stored" + ), + ) + gemachtigde_claim_name = models.CharField( + verbose_name=_("gemachtigde claim name"), + default="gemachtigde.bsn", + max_length=50, + help_text=_( + "Name of the claim in which the BSN of the person representing someone else is stored" + ), + ) + oidc_rp_scopes_list = ArrayField( + verbose_name=_("OpenID Connect scopes"), + base_field=models.CharField(_("OpenID Connect scope"), max_length=50), + default=get_default_scopes_bsn, + blank=True, + help_text=_( + "OpenID Connect scopes that are requested during login. " + "These scopes are hardcoded and must be supported by the identity provider" + ), + ) + + class Meta: + verbose_name = _("OpenID Connect configuration for DigiD Machtigen") + + @property + def digid_eherkenning_machtigen_claims(self) -> dict[str, ClaimPath]: + return { + "vertegenwoordigde": [self.vertegenwoordigde_claim_name], + "gemachtigde": [self.gemachtigde_claim_name], + } + + @property + def oidcdb_sensitive_claims(self) -> Collection[ClaimPath]: + return list(self.digid_eherkenning_machtigen_claims.values()) diff --git a/digid_eherkenning/oidc/models/eherkenning.py b/digid_eherkenning/oidc/models/eherkenning.py new file mode 100644 index 0000000..bef6162 --- /dev/null +++ b/digid_eherkenning/oidc/models/eherkenning.py @@ -0,0 +1,88 @@ +from collections.abc import Collection + +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from django_jsonform.models.fields import ArrayField +from mozilla_django_oidc_db.typing import ClaimPath + +from .base import ( + OpenIDConnectBaseConfig, + get_default_scopes_bsn, + get_default_scopes_kvk, +) + + +class EHerkenningConfig(OpenIDConnectBaseConfig): + """ + Configuration for eHerkenning authentication via OpenID connect + """ + + identifier_claim_name = models.CharField( + _("KVK claim name"), + max_length=100, + help_text=_("The name of the claim in which the KVK of the user is stored"), + default="kvk", + ) + oidc_rp_scopes_list = ArrayField( + verbose_name=_("OpenID Connect scopes"), + base_field=models.CharField(_("OpenID Connect scope"), max_length=50), + default=get_default_scopes_kvk, + blank=True, + help_text=_( + "OpenID Connect scopes that are requested during login. " + "These scopes are hardcoded and must be supported by the identity provider" + ), + ) + + class Meta: + verbose_name = _("OpenID Connect configuration for eHerkenning") + + @property + def oidcdb_username_claim(self) -> list[str]: + return [self.identifier_claim_name] + + +class EHerkenningBewindvoeringConfig(OpenIDConnectBaseConfig): + # TODO: support periods in claim keys + vertegenwoordigde_company_claim_name = models.CharField( + verbose_name=_("vertegenwoordigde company claim name"), + default="aanvrager.kvk", + max_length=50, + help_text=_( + "Name of the claim in which the KVK of the company being represented is stored" + ), + ) + gemachtigde_person_claim_name = models.CharField( + verbose_name=_("gemachtigde person claim name"), + default="gemachtigde.pseudoID", + max_length=50, + help_text=_( + "Name of the claim in which the ID of the person representing a company is stored" + ), + ) + oidc_rp_scopes_list = ArrayField( + verbose_name=_("OpenID Connect scopes"), + base_field=models.CharField(_("OpenID Connect scope"), max_length=50), + default=get_default_scopes_bsn, + blank=True, + help_text=_( + "OpenID Connect scopes that are requested during login. " + "These scopes are hardcoded and must be supported by the identity provider" + ), + ) + + class Meta: + verbose_name = _("OpenID Connect configuration for eHerkenning Bewindvoering") + + @property + def digid_eherkenning_machtigen_claims(self) -> dict[str, ClaimPath]: + # TODO: this nomenclature isn't entirely correct + return { + "vertegenwoordigde": [self.vertegenwoordigde_company_claim_name], + "gemachtigde": [self.gemachtigde_person_claim_name], + } + + @property + def oidcdb_sensitive_claims(self) -> Collection[ClaimPath]: + return list(self.digid_eherkenning_machtigen_claims.values())