Skip to content

Commit

Permalink
Convert models to concrete models
Browse files Browse the repository at this point in the history
Removed the inheritance from abstract base models to
simplify the dependency on mozilla_django_oidc_db, by
temporarily vendoring in all the relevant model fields
code.
  • Loading branch information
sergei-maertens committed Jul 5, 2024
1 parent 3eaf384 commit c3c4315
Showing 1 changed file with 227 additions and 32 deletions.
259 changes: 227 additions & 32 deletions src/digid_eherkenning_oidc_generics/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django_jsonform.models.fields import ArrayField
from mozilla_django_oidc_db.models import OpenIDConnectConfigBase
from solo.models import SingletonModel

from .digid_settings import DIGID_CUSTOM_OIDC_DB_PREFIX
from .eherkenning_settings import EHERKENNING_CUSTOM_OIDC_DB_PREFIX
Expand Down Expand Up @@ -62,35 +63,132 @@ class Meta:
abstract = True


class OpenIDConnectDigiDConfig(OpenIDConnectBaseConfig):
class OpenIDConnectDigiDConfig(SingletonModel):
"""
Configuration for DigiD authentication via OpenID connect
"""

oidc_rp_client_id = models.CharField(
help_text="OpenID Connect client ID provided by the OIDC Provider",
max_length=1000,
verbose_name="OpenID Connect client ID",
)
oidc_rp_client_secret = models.CharField(
help_text="OpenID Connect secret provided by the OIDC Provider",
max_length=1000,
verbose_name="OpenID Connect secret",
)
oidc_rp_sign_algo = models.CharField(
default="HS256",
help_text="Algorithm the Identity Provider uses to sign ID tokens",
max_length=50,
verbose_name="OpenID sign algorithm",
)
oidc_op_discovery_endpoint = models.URLField(
blank=True,
help_text="URL of your OpenID Connect provider discovery endpoint ending with a slash (`.well-known/...` will be added automatically). If this is provided, the remaining endpoints can be omitted, as they will be derived from this endpoint.",
max_length=1000,
verbose_name="Discovery endpoint",
)
oidc_op_jwks_endpoint = models.URLField(
blank=True,
help_text="URL of your OpenID Connect provider JSON Web Key Set endpoint. Required if `RS256` is used as signing algorithm.",
max_length=1000,
verbose_name="JSON Web Key Set endpoint",
)
oidc_op_authorization_endpoint = models.URLField(
help_text="URL of your OpenID Connect provider authorization endpoint",
max_length=1000,
verbose_name="Authorization endpoint",
)
oidc_op_token_endpoint = models.URLField(
help_text="URL of your OpenID Connect provider token endpoint",
max_length=1000,
verbose_name="Token endpoint",
)
oidc_op_user_endpoint = models.URLField(
help_text="URL of your OpenID Connect provider userinfo endpoint",
max_length=1000,
verbose_name="User endpoint",
)
oidc_rp_idp_sign_key = models.CharField(
blank=True,
help_text="Key the Identity Provider uses to sign ID tokens in the case of an RSA sign algorithm. Should be the signing key in PEM or DER format.",
max_length=1000,
verbose_name="Sign key",
)
oidc_use_nonce = models.BooleanField(
default=True,
help_text="Controls whether the OpenID Connect client uses nonce verification",
verbose_name="Use nonce",
)
oidc_nonce_size = models.PositiveIntegerField(
default=32,
help_text="Sets the length of the random string used for OpenID Connect nonce verification",
verbose_name="Nonce size",
)
oidc_state_size = models.PositiveIntegerField(
default=32,
help_text="Sets the length of the random string used for OpenID Connect state verification",
verbose_name="State size",
)
oidc_exempt_urls = ArrayField(
base_field=models.CharField(max_length=1000, verbose_name="Exempt URL"),
blank=True,
default=list,
help_text="This is a list of absolute url paths, regular expressions for url paths, or Django view names. This plus the mozilla-django-oidc urls are exempted from the session renewal by the SessionRefresh middleware.",
size=None,
verbose_name="URLs exempt from session renewal",
)
userinfo_claims_source = models.CharField(
choices=[
("userinfo_endpoint", "Userinfo endpoint"),
("id_token", "ID token"),
],
default="userinfo_endpoint",
help_text="Indicates the source from which the user information claims should be extracted.",
max_length=100,
verbose_name="user information claims extracted from",
)
oidc_op_logout_endpoint = models.URLField(
blank=True,
help_text="URL of your OpenID Connect provider logout endpoint",
max_length=1000,
verbose_name="Logout endpoint",
)
oidc_keycloak_idp_hint = models.CharField(
blank=True,
help_text="Specific for Keycloak: parameter that indicates which identity provider should be used (therefore skipping the Keycloak login screen).",
max_length=1000,
verbose_name="Keycloak Identity Provider hint",
)
enabled = models.BooleanField(
_("enable"),
default=False,
help_text=_(
"Indicates whether OpenID Connect for authentication/authorization is enabled. "
"This overrides overrides the usage of SAML for DigiD authentication."
),
help_text="Indicates whether OpenID Connect for authentication/authorization is enabled. This overrides overrides the usage of SAML for DigiD authentication.",
verbose_name="enable",
)

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",
help_text="The name of the claim in which the BSN of the user is stored",
max_length=100,
verbose_name="BSN claim name",
)
oidc_rp_scopes_list = ArrayField(
verbose_name=_("OpenID Connect scopes"),
base_field=models.CharField(_("OpenID Connect scope"), max_length=50),
base_field=models.CharField(max_length=50, verbose_name="OpenID Connect scope"),
blank=True,
default=get_default_scopes_bsn,
help_text="OpenID Connect scopes that are requested during login. These scopes are hardcoded and must be supported by the identity provider",
size=None,
verbose_name="OpenID Connect scopes",
)

# TODO: this is not in django-digid-eherkenning
error_message_mapping = models.JSONField(
blank=True,
help_text=_(
"OpenID Connect scopes that are requested during login. "
"These scopes are hardcoded and must be supported by the identity provider"
),
default=dict,
help_text="Mapping that maps error messages returned by the identity provider to human readable error messages that are shown to the user",
max_length=1000,
verbose_name="Error message mapping",
)

@classproperty
Expand All @@ -102,35 +200,132 @@ class Meta:
db_table = "digid_eherkenning_oidc_generics_openidconnectdigidconfig"


class OpenIDConnectEHerkenningConfig(OpenIDConnectBaseConfig):
class OpenIDConnectEHerkenningConfig(SingletonModel):
"""
Configuration for eHerkenning authentication via OpenID connect
"""

oidc_rp_client_id = models.CharField(
help_text="OpenID Connect client ID provided by the OIDC Provider",
max_length=1000,
verbose_name="OpenID Connect client ID",
)
oidc_rp_client_secret = models.CharField(
help_text="OpenID Connect secret provided by the OIDC Provider",
max_length=1000,
verbose_name="OpenID Connect secret",
)
oidc_rp_sign_algo = models.CharField(
default="HS256",
help_text="Algorithm the Identity Provider uses to sign ID tokens",
max_length=50,
verbose_name="OpenID sign algorithm",
)
oidc_op_discovery_endpoint = models.URLField(
blank=True,
help_text="URL of your OpenID Connect provider discovery endpoint ending with a slash (`.well-known/...` will be added automatically). If this is provided, the remaining endpoints can be omitted, as they will be derived from this endpoint.",
max_length=1000,
verbose_name="Discovery endpoint",
)
oidc_op_jwks_endpoint = models.URLField(
blank=True,
help_text="URL of your OpenID Connect provider JSON Web Key Set endpoint. Required if `RS256` is used as signing algorithm.",
max_length=1000,
verbose_name="JSON Web Key Set endpoint",
)
oidc_op_authorization_endpoint = models.URLField(
help_text="URL of your OpenID Connect provider authorization endpoint",
max_length=1000,
verbose_name="Authorization endpoint",
)
oidc_op_token_endpoint = models.URLField(
help_text="URL of your OpenID Connect provider token endpoint",
max_length=1000,
verbose_name="Token endpoint",
)
oidc_op_user_endpoint = models.URLField(
help_text="URL of your OpenID Connect provider userinfo endpoint",
max_length=1000,
verbose_name="User endpoint",
)
oidc_rp_idp_sign_key = models.CharField(
blank=True,
help_text="Key the Identity Provider uses to sign ID tokens in the case of an RSA sign algorithm. Should be the signing key in PEM or DER format.",
max_length=1000,
verbose_name="Sign key",
)
oidc_use_nonce = models.BooleanField(
default=True,
help_text="Controls whether the OpenID Connect client uses nonce verification",
verbose_name="Use nonce",
)
oidc_nonce_size = models.PositiveIntegerField(
default=32,
help_text="Sets the length of the random string used for OpenID Connect nonce verification",
verbose_name="Nonce size",
)
oidc_state_size = models.PositiveIntegerField(
default=32,
help_text="Sets the length of the random string used for OpenID Connect state verification",
verbose_name="State size",
)
oidc_exempt_urls = ArrayField(
base_field=models.CharField(max_length=1000, verbose_name="Exempt URL"),
blank=True,
default=list,
help_text="This is a list of absolute url paths, regular expressions for url paths, or Django view names. This plus the mozilla-django-oidc urls are exempted from the session renewal by the SessionRefresh middleware.",
size=None,
verbose_name="URLs exempt from session renewal",
)
userinfo_claims_source = models.CharField(
choices=[
("userinfo_endpoint", "Userinfo endpoint"),
("id_token", "ID token"),
],
default="userinfo_endpoint",
help_text="Indicates the source from which the user information claims should be extracted.",
max_length=100,
verbose_name="user information claims extracted from",
)
oidc_op_logout_endpoint = models.URLField(
blank=True,
help_text="URL of your OpenID Connect provider logout endpoint",
max_length=1000,
verbose_name="Logout endpoint",
)
oidc_keycloak_idp_hint = models.CharField(
blank=True,
help_text="Specific for Keycloak: parameter that indicates which identity provider should be used (therefore skipping the Keycloak login screen).",
max_length=1000,
verbose_name="Keycloak Identity Provider hint",
)
enabled = models.BooleanField(
_("enable"),
default=False,
help_text=_(
"Indicates whether OpenID Connect for authentication/authorization is enabled. "
"This overrides overrides the usage of SAML for eHerkenning authentication."
),
help_text="Indicates whether OpenID Connect for authentication/authorization is enabled. This overrides overrides the usage of SAML for eHerkenning authentication.",
verbose_name="enable",
)

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",
help_text="The name of the claim in which the KVK of the user is stored",
max_length=100,
verbose_name="KVK claim name",
)
oidc_rp_scopes_list = ArrayField(
verbose_name=_("OpenID Connect scopes"),
base_field=models.CharField(_("OpenID Connect scope"), max_length=50),
base_field=models.CharField(max_length=50, verbose_name="OpenID Connect scope"),
blank=True,
default=get_default_scopes_kvk,
help_text="OpenID Connect scopes that are requested during login. These scopes are hardcoded and must be supported by the identity provider",
size=None,
verbose_name="OpenID Connect scopes",
)

# TODO: this is not in django-digid-eherkenning
error_message_mapping = models.JSONField(
blank=True,
help_text=_(
"OpenID Connect scopes that are requested during login. "
"These scopes are hardcoded and must be supported by the identity provider"
),
default=dict,
help_text="Mapping that maps error messages returned by the identity provider to human readable error messages that are shown to the user",
max_length=1000,
verbose_name="Error message mapping",
)

@classproperty
Expand Down

0 comments on commit c3c4315

Please sign in to comment.