From 92e7afd10c4b70942f56c5c3466fb5b32894fded Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Mon, 11 Apr 2022 11:25:42 +0200 Subject: [PATCH] :construction: [#45] Initial changes for endpoints config --- .../migrations/0007_auto_20220411_1011.py | 85 +++++++++++++++++++ .../migrations/0008_auto_20220411_1015.py | 43 ++++++++++ mozilla_django_oidc_db/models.py | 51 +++++++++++ mozilla_django_oidc_db/utils.py | 42 +++++++++ 4 files changed, 221 insertions(+) create mode 100644 mozilla_django_oidc_db/migrations/0007_auto_20220411_1011.py create mode 100644 mozilla_django_oidc_db/migrations/0008_auto_20220411_1015.py create mode 100644 mozilla_django_oidc_db/utils.py diff --git a/mozilla_django_oidc_db/migrations/0007_auto_20220411_1011.py b/mozilla_django_oidc_db/migrations/0007_auto_20220411_1011.py new file mode 100644 index 0000000..46e2b26 --- /dev/null +++ b/mozilla_django_oidc_db/migrations/0007_auto_20220411_1011.py @@ -0,0 +1,85 @@ +# Generated by Django 3.2.12 on 2022-04-11 08:11 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("mozilla_django_oidc_db", "0006_openidconnectconfig_unique_id_claim"), + ] + + operations = [ + migrations.CreateModel( + name="OpenIDConnectEndpointsConfig", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "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", + ), + ), + ], + options={ + "verbose_name": "OpenID Connect endpoint configuration", + "verbose_name_plural": "OpenID Connect endpoint configurations", + }, + ), + migrations.AddField( + model_name="openidconnectconfig", + name="endpoints_config", + field=models.ForeignKey( + blank=True, + help_text="Model containing the endpoint configuration for the OpenID Connect provider", + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="mozilla_django_oidc_db.openidconnectendpointsconfig", + ), + ), + ] diff --git a/mozilla_django_oidc_db/migrations/0008_auto_20220411_1015.py b/mozilla_django_oidc_db/migrations/0008_auto_20220411_1015.py new file mode 100644 index 0000000..5d94749 --- /dev/null +++ b/mozilla_django_oidc_db/migrations/0008_auto_20220411_1015.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.12 on 2022-04-11 08:15 + +from django.db import migrations + +from mozilla_django_oidc_db.utils import ( + migrate_endpoints_backward, + migrate_endpoints_forward, +) + + +def migrate_endpoints(apps, schema_editor): + OpenIDConnectConfig = apps.get_model( + "mozilla_django_oidc_db", "OpenIDConnectConfig" + ) + OpenIDConnectEndpointsConfig = apps.get_model( + "mozilla_django_oidc_db", "OpenIDConnectEndpointsConfig" + ) + + migrate_endpoints_forward(OpenIDConnectConfig, OpenIDConnectEndpointsConfig) + + +def migrate_endpoints_reverse(apps, schema_editor): + OpenIDConnectConfig = apps.get_model( + "mozilla_django_oidc_db", "OpenIDConnectConfig" + ) + OpenIDConnectEndpointsConfig = apps.get_model( + "mozilla_django_oidc_db", "OpenIDConnectEndpointsConfig" + ) + + migrate_endpoints_backward(OpenIDConnectConfig, OpenIDConnectEndpointsConfig) + + +class Migration(migrations.Migration): + + dependencies = [ + ("mozilla_django_oidc_db", "0007_auto_20220411_1011"), + ] + + operations = [ + migrations.RunPython( + migrate_endpoints, reverse_code=migrate_endpoints_reverse + ), + ] diff --git a/mozilla_django_oidc_db/models.py b/mozilla_django_oidc_db/models.py index 7706ab4..67b791b 100644 --- a/mozilla_django_oidc_db/models.py +++ b/mozilla_django_oidc_db/models.py @@ -90,6 +90,47 @@ def get_solo(cls) -> SingletonModel: return obj +class OpenIDConnectEndpointsConfig(models.Model): + oidc_op_discovery_endpoint = models.URLField( + _("Discovery endpoint"), + max_length=1000, + 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." + ), + blank=True, + ) + oidc_op_jwks_endpoint = models.URLField( + _("JSON Web Key Set endpoint"), + max_length=1000, + help_text=_( + "URL of your OpenID Connect provider JSON Web Key Set endpoint. Required if `RS256` is used as signing algorithm" + ), + blank=True, + ) + oidc_op_authorization_endpoint = models.URLField( + _("Authorization endpoint"), + max_length=1000, + help_text=_("URL of your OpenID Connect provider authorization endpoint"), + ) + oidc_op_token_endpoint = models.URLField( + _("Token endpoint"), + max_length=1000, + help_text=_("URL of your OpenID Connect provider token endpoint"), + ) + oidc_op_user_endpoint = models.URLField( + _("User endpoint"), + max_length=1000, + help_text=_("URL of your OpenID Connect provider userinfo endpoint"), + ) + + class Meta: + verbose_name = _("OpenID Connect endpoint configuration") + verbose_name_plural = _("OpenID Connect endpoint configurations") + + class OpenIDConnectConfigBase(SingletonModel): """ Defines the required fields for a config to establish an OIDC connection @@ -127,6 +168,16 @@ class OpenIDConnectConfigBase(SingletonModel): help_text=_("OpenID Connect scopes that are requested during login"), ) + endpoints_config = models.ForeignKey( + OpenIDConnectEndpointsConfig, + null=True, + blank=True, + on_delete=models.DO_NOTHING, + help_text=_( + "Model containing the endpoint configuration for the OpenID Connect provider" + ), + ) + oidc_op_discovery_endpoint = models.URLField( _("Discovery endpoint"), max_length=1000, diff --git a/mozilla_django_oidc_db/utils.py b/mozilla_django_oidc_db/utils.py new file mode 100644 index 0000000..d02c791 --- /dev/null +++ b/mozilla_django_oidc_db/utils.py @@ -0,0 +1,42 @@ +from django.db import models + +from solo.models import SingletonModel + + +def migrate_endpoints_forward( + config_singleton_model: SingletonModel, endpoints_config_model: models.Model +): + config = config_singleton_model.objects.first() + if not config or config.endpoints_config: + return + + endpoints_config = endpoints_config_model.objects.create( + oidc_op_discovery_endpoint=config.oidc_op_discovery_endpoint, + oidc_op_jwks_endpoint=config.oidc_op_jwks_endpoint, + oidc_op_authorization_endpoint=config.oidc_op_authorization_endpoint, + oidc_op_token_endpoint=config.oidc_op_token_endpoint, + oidc_op_user_endpoint=config.oidc_op_user_endpoint, + ) + + config.endpoints_config = endpoints_config + config.save() + + +def migrate_endpoints_backward( + config_singleton_model: SingletonModel, endpoints_config_model: models.Model +): + config = config_singleton_model.objects.first() + if not config or not config.endpoints_config: + return + + config.oidc_op_discovery_endpoint = ( + config.endpoints_config.oidc_op_discovery_endpoint + ) + config.oidc_op_jwks_endpoint = config.endpoints_config.oidc_op_jwks_endpoint + config.oidc_op_authorization_endpoint = ( + config.endpoints_config.oidc_op_authorization_endpoint + ) + config.oidc_op_token_endpoint = config.endpoints_config.oidc_op_token_endpoint + config.oidc_op_user_endpoint = config.endpoints_config.oidc_op_user_endpoint + + config.save()