diff --git a/bin/setup_configuration.sh b/bin/setup_configuration.sh index 844ba43..93ab4db 100755 --- a/bin/setup_configuration.sh +++ b/bin/setup_configuration.sh @@ -1,6 +1,6 @@ #!/bin/bash -# setup initial configuration using environment variables +# setup initial configuration using a yaml file # Run this script from the root of the repository set -e diff --git a/docker/setup_configuration/data.yaml b/docker/setup_configuration/data.yaml index 2b89efd..6c6024d 100644 --- a/docker/setup_configuration/data.yaml +++ b/docker/setup_configuration/data.yaml @@ -13,4 +13,18 @@ sites_config_enable: true sites_config: items: - domain: example.com - name: example \ No newline at end of file + name: example + +oidc_db_config_enable: true +oidc_db_config_admin_auth: + items: + - identifier: admin-oidc + oidc_rp_client_id: client-id + oidc_rp_client_secret: secret + endpoint_config: + oidc_op_authorization_endpoint: https://example.com/realms/test/protocol/openid-connect/auth + oidc_op_token_endpoint: https://example.com/realms/test/protocol/openid-connect/token + oidc_op_user_endpoint: https://example.com/realms/test/protocol/openid-connect/userinfo + + # workaround for https://github.com/maykinmedia/django-setup-configuration/issues/27 + userinfo_claims_source: id_token diff --git a/requirements/base.in b/requirements/base.in index 8d6f74f..657f868 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -8,6 +8,7 @@ furl django-jsonsuit sharing-configs django-setup-configuration>=0.4.0 +mozilla-django-oidc-db[django-setup-configuration] # API libraries drf-nested-routers diff --git a/requirements/base.txt b/requirements/base.txt index 8c4d6a2..d1a9193 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -195,7 +195,9 @@ drf-nested-routers==0.94.1 # -r requirements/base.in # commonground-api-common drf-spectacular[sidecar]==0.27.2 - # via open-api-framework + # via + # drf-spectacular + # open-api-framework drf-spectacular-sidecar==2024.7.1 # via drf-spectacular drf-yasg==1.21.7 @@ -244,8 +246,10 @@ maykin-2fa==1.0.1 # via open-api-framework mozilla-django-oidc==4.0.0 # via mozilla-django-oidc-db -mozilla-django-oidc-db==0.19.0 - # via open-api-framework +mozilla-django-oidc-db[django-setup-configuration]==0.21.1 + # via + # -r requirements/base.in + # open-api-framework notifications-api-common==0.3.1 # via commonground-api-common open-api-framework==0.9.0 @@ -273,7 +277,9 @@ pydantic==2.9.2 pydantic-core==2.23.4 # via pydantic pydantic-settings[yaml]==2.6.1 - # via django-setup-configuration + # via + # django-setup-configuration + # pydantic-settings pyjwt==2.7.0 # via # commonground-api-common diff --git a/requirements/ci.txt b/requirements/ci.txt index 53e47df..3ea0799 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -262,6 +262,7 @@ django-solo==2.0.0 django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via # -r requirements/base.txt + # django-two-factor-auth # maykin-2fa django-webtest==1.9.10 # via -r requirements/test-tools.in @@ -296,6 +297,7 @@ drf-nested-routers==0.94.1 drf-spectacular[sidecar]==0.27.2 # via # -r requirements/base.txt + # drf-spectacular # open-api-framework drf-spectacular-sidecar==2024.7.1 # via @@ -397,9 +399,10 @@ mozilla-django-oidc==4.0.0 # via # -r requirements/base.txt # mozilla-django-oidc-db -mozilla-django-oidc-db==0.19.0 +mozilla-django-oidc-db[django-setup-configuration]==0.21.1 # via # -r requirements/base.txt + # mozilla-django-oidc-db # open-api-framework multidict==6.0.5 # via yarl @@ -463,6 +466,7 @@ pydantic-settings[yaml]==2.6.1 # via # -r requirements/base.txt # django-setup-configuration + # pydantic-settings pyflakes==3.2.0 # via flake8 pyjwt==2.7.0 diff --git a/requirements/dev.txt b/requirements/dev.txt index d98a302..db2ae30 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -273,6 +273,7 @@ django-solo==2.0.0 django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via # -r requirements/base.txt + # django-two-factor-auth # maykin-2fa django-webtest==1.9.10 # via -r requirements/test-tools.in @@ -311,6 +312,7 @@ drf-nested-routers==0.94.1 drf-spectacular[sidecar]==0.27.2 # via # -r requirements/base.txt + # drf-spectacular # open-api-framework drf-spectacular-sidecar==2024.7.1 # via @@ -415,9 +417,10 @@ mozilla-django-oidc==4.0.0 # via # -r requirements/base.txt # mozilla-django-oidc-db -mozilla-django-oidc-db==0.19.0 +mozilla-django-oidc-db[django-setup-configuration]==0.21.1 # via # -r requirements/base.txt + # mozilla-django-oidc-db # open-api-framework multidict==6.0.5 # via yarl @@ -485,6 +488,7 @@ pydantic-settings[yaml]==2.6.1 # via # -r requirements/base.txt # django-setup-configuration + # pydantic-settings pyflakes==3.0.1 # via flake8 pygments==2.15.1 diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 60bbf72..c409904 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -52,6 +52,6 @@ # Django setup configuration # SETUP_CONFIGURATION_STEPS = [ - "objecttypes.setup_configuration.steps.sites.SitesConfigurationStep", "objecttypes.setup_configuration.steps.token_auth.TokenAuthConfigurationStep", + "mozilla_django_oidc_db.setup_configuration.steps.AdminOIDCConfigurationStep", ] diff --git a/src/objecttypes/setup_configuration/models/sites.py b/src/objecttypes/setup_configuration/models/sites.py deleted file mode 100644 index 360bdbb..0000000 --- a/src/objecttypes/setup_configuration/models/sites.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.contrib.sites.models import Site - -from django_setup_configuration.models import ConfigurationModel - - -class SiteConfigurationModel(ConfigurationModel): - class Meta: - django_model_refs = { - Site: ( - "domain", - "name", - ) - } - - -class SitesConfigurationModel(ConfigurationModel): - items: list[SiteConfigurationModel] diff --git a/src/objecttypes/setup_configuration/steps/sites.py b/src/objecttypes/setup_configuration/steps/sites.py deleted file mode 100644 index b5993d1..0000000 --- a/src/objecttypes/setup_configuration/steps/sites.py +++ /dev/null @@ -1,58 +0,0 @@ -import logging - -from django.contrib.sites.models import Site -from django.core.exceptions import ValidationError -from django.db import IntegrityError - -from django_setup_configuration.configuration import BaseConfigurationStep -from django_setup_configuration.exceptions import ConfigurationRunFailed - -from objecttypes.setup_configuration.models.sites import SitesConfigurationModel - -logger = logging.getLogger(__name__) - - -class SitesConfigurationStep(BaseConfigurationStep[SitesConfigurationModel]): - """ - Configure the application site/domain. - """ - - namespace = "sites_config" - enable_setting = "sites_config_enable" - - verbose_name = "Configuration to set up Sites for ObjectTypes" - config_model = SitesConfigurationModel - - def execute(self, model: SitesConfigurationModel) -> None: - for item in model.items: - logger.info(f"Configuring {item.domain}") - - model_kwargs = { - "domain": item.domain, - "name": item.name, - } - - instance = Site(**model_kwargs) - - try: - instance.full_clean(exclude=("id",), validate_unique=False) - except ValidationError as exception: - exception_message = f"Validation error(s) occured for {item.domain}." - raise ConfigurationRunFailed(exception_message) from exception - - logger.debug(f"No validation errors found for {item.domain}") - - try: - logger.debug(f"Saving {item.domain}") - Site.objects.update_or_create( - domain=item.domain, - defaults={ - "name": item.name, - }, - ) - - except IntegrityError as exception: - exception_message = f"Failed configuring token {item.domain}." - raise ConfigurationRunFailed(exception_message) from exception - - logger.info(f"Configured {item.domain}") diff --git a/src/objecttypes/setup_configuration/tests/files/sites/invalid_setup.yaml b/src/objecttypes/setup_configuration/tests/files/sites/invalid_setup.yaml deleted file mode 100644 index c6bda53..0000000 --- a/src/objecttypes/setup_configuration/tests/files/sites/invalid_setup.yaml +++ /dev/null @@ -1,3 +0,0 @@ -sites_config_enable: true -sites_config: - items: \ No newline at end of file diff --git a/src/objecttypes/setup_configuration/tests/files/sites/valid_setup.yaml b/src/objecttypes/setup_configuration/tests/files/sites/valid_setup.yaml deleted file mode 100644 index 08f6085..0000000 --- a/src/objecttypes/setup_configuration/tests/files/sites/valid_setup.yaml +++ /dev/null @@ -1,8 +0,0 @@ -sites_config_enable: true -sites_config: - items: - - domain: example-1.com - name: example-1 - - - domain: example-2.com - name: example-2 diff --git a/src/objecttypes/setup_configuration/tests/test_sites_config.py b/src/objecttypes/setup_configuration/tests/test_sites_config.py deleted file mode 100644 index a2ee69c..0000000 --- a/src/objecttypes/setup_configuration/tests/test_sites_config.py +++ /dev/null @@ -1,58 +0,0 @@ -from pathlib import Path - -from django.contrib.sites.models import Site -from django.test import TestCase - -from django_setup_configuration.exceptions import PrerequisiteFailed -from django_setup_configuration.test_utils import execute_single_step - -from objecttypes.setup_configuration.steps.sites import SitesConfigurationStep - -DIR_FILES = (Path(__file__).parent / "files/sites").resolve() - - -class SitesConfigurationStepTests(TestCase): - def test_valid_setup_default(self): - self.assertTrue( - Site.objects.filter(domain="example.com", name="example.com").exists() - ) - - execute_single_step( - SitesConfigurationStep, yaml_source=str(DIR_FILES / "valid_setup.yaml") - ) - - sites = Site.objects.all() - self.assertEqual(sites.count(), 3) - self.assertTrue(sites.filter(domain="example-1.com", name="example-1").exists()) - self.assertTrue(sites.filter(domain="example-2.com", name="example-2").exists()) - - def test_valid_update_existing_sites(self): - self.assertTrue( - Site.objects.filter(domain="example.com", name="example.com").exists() - ) - - Site.objects.create(domain="example-2.com", name="example-3") - self.assertEqual(Site.objects.count(), 2) - - execute_single_step( - SitesConfigurationStep, yaml_source=str(DIR_FILES / "valid_setup.yaml") - ) - - sites = Site.objects.all() - self.assertEqual(sites.count(), 3) - self.assertTrue(sites.filter(domain="example-2.com", name="example-2").exists()) - self.assertTrue(sites.filter(domain="example-1.com", name="example-1").exists()) - - def test_invalid_setup(self): - self.assertTrue( - Site.objects.filter(domain="example.com", name="example.com").exists() - ) - - with self.assertRaises(PrerequisiteFailed) as command_error: - execute_single_step( - SitesConfigurationStep, - yaml_source=str(DIR_FILES / "invalid_setup.yaml"), - ) - - self.assertTrue("Input should be a valid list" in str(command_error.exception)) - self.assertEqual(Site.objects.count(), 1) diff --git a/src/objecttypes/setup_configuration/tests/test_token_auth_config.py b/src/objecttypes/setup_configuration/tests/test_token_auth_config.py index 2b494f9..3870595 100644 --- a/src/objecttypes/setup_configuration/tests/test_token_auth_config.py +++ b/src/objecttypes/setup_configuration/tests/test_token_auth_config.py @@ -353,7 +353,6 @@ def test_invalid_setup_identifier(self): } with self.assertRaises(ConfigurationRunFailed) as command_error: execute_single_step(TokenAuthConfigurationStep, object_source=object_source) - self.assertTrue( "Validation error(s) occured for invalid identifier" in str(command_error.exception)