diff --git a/docker/setup_configuration/data.yaml b/docker/setup_configuration/data.yaml index 2b89efd..7d27246 100644 --- a/docker/setup_configuration/data.yaml +++ b/docker/setup_configuration/data.yaml @@ -13,4 +13,15 @@ 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 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..430a7ba 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -244,8 +244,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 @@ -266,11 +268,11 @@ psycopg2==2.9.9 # via open-api-framework pycparser==2.21 # via cffi -pydantic==2.9.2 +pydantic==2.10.3 # via # django-setup-configuration # pydantic-settings -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic pydantic-settings[yaml]==2.6.1 # via django-setup-configuration @@ -338,7 +340,7 @@ sqlparse==0.5.0 # via django tornado==6.4.1 # via flower -typing-extensions==4.11.0 +typing-extensions==4.12.2 # via # mozilla-django-oidc-db # pydantic diff --git a/requirements/ci.txt b/requirements/ci.txt index 53e47df..a89ef90 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -33,13 +33,13 @@ attrs==23.1.0 # -r requirements/base.txt # glom # jsonschema -beautifulsoup4==4.12.2 +beautifulsoup4==4.12.3 # via webtest billiard==4.2.0 # via # -r requirements/base.txt # celery -black==24.8.0 +black==24.10.0 # via -r requirements/test-tools.in bleach==6.1.0 # via @@ -108,7 +108,7 @@ coreschema==0.0.4 # via # -r requirements/base.txt # coreapi -coverage==4.5.4 +coverage==7.6.9 # via # -r requirements/ci.in # codecov @@ -263,7 +263,7 @@ django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via # -r requirements/base.txt # maykin-2fa -django-webtest==1.9.10 +django-webtest==1.9.12 # via -r requirements/test-tools.in djangorestframework==3.15.2 # via @@ -317,9 +317,9 @@ face==20.1.1 # via # -r requirements/base.txt # glom -factory-boy==3.2.1 +factory-boy==3.3.1 # via -r requirements/test-tools.in -faker==18.9.0 +faker==33.1.0 # via factory-boy flake8==7.1.1 # via -r requirements/test-tools.in @@ -327,7 +327,7 @@ flower==2.0.1 # via # -r requirements/base.txt # open-api-framework -freezegun==1.2.2 +freezegun==1.5.1 # via -r requirements/test-tools.in furl==2.1.3 # via @@ -381,7 +381,7 @@ kombu==5.3.5 # via # -r requirements/base.txt # celery -lxml==4.9.2 +lxml==5.3.0 # via pyquery markupsafe==2.1.2 # via @@ -397,11 +397,11 @@ 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 # open-api-framework -multidict==6.0.5 +multidict==6.1.0 # via yarl mypy-extensions==1.0.0 # via black @@ -440,6 +440,8 @@ prompt-toolkit==3.0.38 # via # -r requirements/base.txt # click-repl +propcache==0.2.1 + # via yarl psycopg2==2.9.9 # via # -r requirements/base.txt @@ -450,12 +452,12 @@ pycparser==2.21 # via # -r requirements/base.txt # cffi -pydantic==2.9.2 +pydantic==2.10.3 # via # -r requirements/base.txt # django-setup-configuration # pydantic-settings -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via # -r requirements/base.txt # pydantic @@ -475,7 +477,7 @@ pyopenssl==24.0.0 # -r requirements/base.txt # josepy # webauthn -pyquery==2.0.0 +pyquery==2.0.1 # via -r requirements/test-tools.in pyrsistent==0.19.3 # via @@ -552,21 +554,22 @@ six==1.16.0 # orderedmultidict # python-dateutil # qrcode -soupsieve==2.4.1 +soupsieve==2.6 # via beautifulsoup4 sqlparse==0.5.0 # via # -r requirements/base.txt # django -tblib==1.7.0 +tblib==3.0.0 # via -r requirements/test-tools.in tornado==6.4.1 # via # -r requirements/base.txt # flower -typing-extensions==4.11.0 +typing-extensions==4.12.2 # via # -r requirements/base.txt + # faker # mozilla-django-oidc-db # pydantic # pydantic-core @@ -587,11 +590,12 @@ urllib3==2.2.2 # elastic-apm # requests # sentry-sdk + # vcrpy uwsgi==2.0.24 # via # -r requirements/base.txt # open-api-framework -vcrpy==6.0.1 +vcrpy==6.0.2 # via -r requirements/test-tools.in vine==5.1.0 # via @@ -599,7 +603,7 @@ vine==5.1.0 # amqp # celery # kombu -waitress==2.1.2 +waitress==3.0.2 # via webtest wcwidth==0.2.6 # via @@ -613,16 +617,16 @@ webencodings==0.5.1 # via # -r requirements/base.txt # bleach -webob==1.8.8 +webob==1.8.9 # via webtest -webtest==3.0.0 +webtest==3.0.2 # via django-webtest wrapt==1.14.1 # via # -r requirements/base.txt # elastic-apm # vcrpy -yarl==1.9.4 +yarl==1.18.3 # via vcrpy zgw-consumers==0.35.1 # via diff --git a/requirements/dev.txt b/requirements/dev.txt index d98a302..b45e16f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -4,7 +4,7 @@ # # pip-compile --no-emit-index-url --output-file=requirements/dev.txt requirements/base.txt requirements/dev.in requirements/test-tools.in # -alabaster==0.7.13 +alabaster==1.0.0 # via sphinx amqp==5.1.1 # via @@ -35,15 +35,15 @@ attrs==23.1.0 # -r requirements/base.txt # glom # jsonschema -babel==2.12.1 +babel==2.16.0 # via sphinx -beautifulsoup4==4.12.2 +beautifulsoup4==4.12.3 # via webtest billiard==4.2.0 # via # -r requirements/base.txt # celery -black==24.4.2 +black==24.10.0 # via -r requirements/test-tools.in bleach==6.1.0 # via @@ -54,7 +54,7 @@ boltons==23.0.0 # -r requirements/base.txt # face # glom -build==0.10.0 +build==1.2.2.post1 # via pip-tools bump2version==1.0.1 # via bumpversion @@ -189,9 +189,9 @@ django-csp==3.8 # via # -r requirements/base.txt # open-api-framework -django-debug-toolbar==4.1.0 +django-debug-toolbar==4.4.6 # via -r requirements/dev.in -django-extensions==3.2.1 +django-extensions==3.2.3 # via -r requirements/dev.in django-filter==24.2 # via @@ -274,7 +274,7 @@ django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via # -r requirements/base.txt # maykin-2fa -django-webtest==1.9.10 +django-webtest==1.9.12 # via -r requirements/test-tools.in djangorestframework==3.15.2 # via @@ -300,7 +300,7 @@ djangorestframework-inclusions==1.2.0 # via # -r requirements/base.txt # open-api-framework -docutils==0.18.1 +docutils==0.21.2 # via # sphinx # sphinx-rtd-theme @@ -332,17 +332,17 @@ face==20.1.1 # via # -r requirements/base.txt # glom -factory-boy==3.2.1 +factory-boy==3.3.1 # via -r requirements/test-tools.in -faker==18.9.0 +faker==33.1.0 # via factory-boy -flake8==6.0.0 +flake8==7.1.1 # via -r requirements/test-tools.in flower==2.0.1 # via # -r requirements/base.txt # open-api-framework -freezegun==1.2.2 +freezegun==1.5.1 # via -r requirements/test-tools.in furl==2.1.3 # via @@ -376,7 +376,7 @@ isodate==0.6.1 # via # -r requirements/base.txt # commonground-api-common -isort==5.12.0 +isort==5.13.2 # via -r requirements/test-tools.in itypes==1.2.0 # via @@ -399,7 +399,7 @@ kombu==5.3.5 # via # -r requirements/base.txt # celery -lxml==4.9.2 +lxml==5.3.0 # via pyquery markupsafe==2.1.2 # via @@ -415,11 +415,11 @@ 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 # open-api-framework -multidict==6.0.5 +multidict==6.1.0 # via yarl mypy-extensions==1.0.0 # via black @@ -444,15 +444,15 @@ packaging==23.1 # build # drf-yasg # sphinx -pathspec==0.11.1 +pathspec==0.12.1 # via black phonenumberslite==8.13.30 # via # -r requirements/base.txt # django-two-factor-auth -pip-tools==7.3.0 +pip-tools==7.4.1 # via -r requirements/dev.in -platformdirs==3.5.1 +platformdirs==4.3.6 # via black prometheus-client==0.20.0 # via @@ -462,22 +462,24 @@ prompt-toolkit==3.0.38 # via # -r requirements/base.txt # click-repl +propcache==0.2.1 + # via yarl psycopg2==2.9.9 # via # -r requirements/base.txt # open-api-framework -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via flake8 pycparser==2.21 # via # -r requirements/base.txt # cffi -pydantic==2.9.2 +pydantic==2.10.3 # via # -r requirements/base.txt # django-setup-configuration # pydantic-settings -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via # -r requirements/base.txt # pydantic @@ -485,9 +487,9 @@ pydantic-settings[yaml]==2.6.1 # via # -r requirements/base.txt # django-setup-configuration -pyflakes==3.0.1 +pyflakes==3.2.0 # via flake8 -pygments==2.15.1 +pygments==2.18.0 # via sphinx pyjwt==2.7.0 # via @@ -499,9 +501,11 @@ pyopenssl==24.0.0 # -r requirements/base.txt # josepy # webauthn -pyproject-hooks==1.0.0 - # via build -pyquery==2.0.0 +pyproject-hooks==1.2.0 + # via + # build + # pip-tools +pyquery==2.0.1 # via -r requirements/test-tools.in pyrsistent==0.19.3 # via @@ -580,43 +584,44 @@ six==1.16.0 # qrcode snowballstemmer==2.2.0 # via sphinx -soupsieve==2.4.1 +soupsieve==2.6 # via beautifulsoup4 -sphinx==6.2.1 +sphinx==8.1.3 # via # -r requirements/dev.in # sphinx-rtd-theme # sphinxcontrib-jquery -sphinx-rtd-theme==1.2.0 +sphinx-rtd-theme==3.0.2 # via -r requirements/dev.in -sphinxcontrib-applehelp==1.0.4 +sphinxcontrib-applehelp==2.0.0 # via sphinx -sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-devhelp==2.0.0 # via sphinx -sphinxcontrib-htmlhelp==2.0.1 +sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-qthelp==2.0.0 # via sphinx -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==2.0.0 # via sphinx sqlparse==0.5.0 # via # -r requirements/base.txt # django # django-debug-toolbar -tblib==1.7.0 +tblib==3.0.0 # via -r requirements/test-tools.in tornado==6.4.1 # via # -r requirements/base.txt # flower -typing-extensions==4.11.0 +typing-extensions==4.12.2 # via # -r requirements/base.txt + # faker # mozilla-django-oidc-db # pydantic # pydantic-core @@ -637,11 +642,12 @@ urllib3==2.2.2 # elastic-apm # requests # sentry-sdk + # vcrpy uwsgi==2.0.24 # via # -r requirements/base.txt # open-api-framework -vcrpy==6.0.1 +vcrpy==6.0.2 # via -r requirements/test-tools.in vine==5.1.0 # via @@ -649,7 +655,7 @@ vine==5.1.0 # amqp # celery # kombu -waitress==2.1.2 +waitress==3.0.2 # via webtest wcwidth==0.2.6 # via @@ -663,18 +669,18 @@ webencodings==0.5.1 # via # -r requirements/base.txt # bleach -webob==1.8.8 +webob==1.8.9 # via webtest -webtest==3.0.0 +webtest==3.0.2 # via django-webtest -wheel==0.40.0 +wheel==0.45.1 # via pip-tools wrapt==1.14.1 # via # -r requirements/base.txt # elastic-apm # vcrpy -yarl==1.9.4 +yarl==1.18.3 # via vcrpy zgw-consumers==0.35.1 # via diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 60bbf72..d18641a 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -54,4 +54,5 @@ SETUP_CONFIGURATION_STEPS = [ "objecttypes.setup_configuration.steps.sites.SitesConfigurationStep", "objecttypes.setup_configuration.steps.token_auth.TokenAuthConfigurationStep", + "objecttypes.setup_configuration.steps.TokenAuthConfigurationStep", ] diff --git a/src/objecttypes/setup_configuration/tests/files/oidc/invalid_setup.yaml b/src/objecttypes/setup_configuration/tests/files/oidc/invalid_setup.yaml new file mode 100644 index 0000000..c218f2b --- /dev/null +++ b/src/objecttypes/setup_configuration/tests/files/oidc/invalid_setup.yaml @@ -0,0 +1,10 @@ +oidc_db_config_enable: true +oidc_db_config_admin_auth: + items: + - identifier: admin-oidc + oidc_rp_client_id: client-id + oidc_rp_client_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 diff --git a/src/objecttypes/setup_configuration/tests/files/oidc/valid_setup.yaml b/src/objecttypes/setup_configuration/tests/files/oidc/valid_setup.yaml new file mode 100644 index 0000000..a00c9a5 --- /dev/null +++ b/src/objecttypes/setup_configuration/tests/files/oidc/valid_setup.yaml @@ -0,0 +1,10 @@ +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 diff --git a/src/objecttypes/setup_configuration/tests/test_oidc_config.py b/src/objecttypes/setup_configuration/tests/test_oidc_config.py new file mode 100644 index 0000000..3716a59 --- /dev/null +++ b/src/objecttypes/setup_configuration/tests/test_oidc_config.py @@ -0,0 +1,69 @@ +from pathlib import Path + +from django.test import TestCase + +from django_setup_configuration.exceptions import ConfigurationException +from django_setup_configuration.test_utils import execute_single_step +from mozilla_django_oidc_db.models import OpenIDConnectConfig +from mozilla_django_oidc_db.setup_configuration.steps import AdminOIDCConfigurationStep + +DIR_FILES = (Path(__file__).parent / "files/oidc").resolve() + + +class AdminOIDCConfigurationTests(TestCase): + + def setUp(self): + OpenIDConnectConfig.clear_cache() + + def test_valid_setup_default(self): + config = OpenIDConnectConfig.get_solo() + self.assertFalse(config.enabled) + + execute_single_step( + AdminOIDCConfigurationStep, + yaml_source=str(DIR_FILES / "valid_setup.yaml"), + ) + + config = OpenIDConnectConfig.get_solo() + + self.assertTrue(config.enabled) + self.assertEqual(config.oidc_rp_client_id, "client-id") + self.assertEqual(config.oidc_rp_client_secret, "secret") + self.assertEqual( + config.oidc_op_authorization_endpoint, + "https://example.com/realms/test/protocol/openid-connect/auth", + ) + self.assertEqual( + config.oidc_op_token_endpoint, + "https://example.com/realms/test/protocol/openid-connect/token", + ) + self.assertEqual( + config.oidc_op_user_endpoint, + "https://example.com/realms/test/protocol/openid-connect/userinfo", + ) + + def test_invalid_setup_default(self): + + config = OpenIDConnectConfig.get_solo() + self.assertFalse(config.enabled) + + with self.assertRaises(ConfigurationException) as command_error: + execute_single_step( + AdminOIDCConfigurationStep, + yaml_source=str(DIR_FILES / "invalid_setup.yaml"), + ) + + self.assertTrue( + "Input should be a valid string" in str(command_error.exception) + ) + + config = OpenIDConnectConfig.get_solo() + + self.assertFalse(config.enabled) + self.assertEqual(config.oidc_rp_client_id, "") + self.assertEqual(config.oidc_rp_client_secret, "") + self.assertEqual(config.oidc_op_authorization_endpoint, "") + self.assertEqual(config.oidc_op_token_endpoint, "") + self.assertEqual(config.oidc_op_user_endpoint, "") + + self.assertFalse(OpenIDConnectConfig.get_solo().enabled)