diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 11870338..86e73877 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,20 @@
Changes
=======
+1.x.x (TBD)
+-----------
+**Bugfixes and QOL**
+
+* [#66] updated commonground-api-common to 2.1.0 (TBD)
+
+.. warning::
+
+ Configuring external services is now done through the `Service` model. This
+ replaces the `APICredential` model in the admin interface. A data migration
+ was added to move to the `Service` model. It is advised to verify the `Service`
+ instances in the admin to check that the data migration was ran as expected.
+
+
1.7.1 (2024-10-04)
------------------
diff --git a/docs/installation/configuration/opennotifs_config.rst b/docs/installation/configuration/opennotifs_config.rst
index 5ad23a87..c7040964 100644
--- a/docs/installation/configuration/opennotifs_config.rst
+++ b/docs/installation/configuration/opennotifs_config.rst
@@ -36,17 +36,19 @@ using Open Zaak as the example.
1. Configure the credentials for the Open Zaak Autorisaties API (so Open
Notificaties can access the Autorisaties API):
- a. Navigate to **API Autorisaties > Externe API credentials**
- b. Click **Externe API credential toevoegen**.
+ a. Navigate to **API Autorisaties > Services**
+ b. Click **Service toevoegen**.
c. Fill out the form:
- - **API root**: *The URL of the Open Zaak Autorisaties API endpoint*
+ - **Api root url**: *The URL of the Open Zaak Autorisaties API endpoint*
- **Label**: *For example:* ``Open Zaak Autorisaties``
- - **Client ID**: *For example:* ``open-notificaties``
+ - **Client id**: *For example:* ``open-notificaties``
- **Secret**: *Some random string*
- - **User ID**: *Same as the Client ID*
- - **User representation**: *For example:* ``Open Notificaties``
+ - **Authorization type**: *ZGW client_id + secret*
+ - **Gebruikers ID**: *Same as the Client ID*
+ - **Gebruikersweergave**: *For example:* ``Open Notificaties``
+ - **Service slug**: *For example:* ``authorization-api-service``
Make sure Open Notificaties is authorized in Open Zaak to access the
Autorisaties API by using the same Client ID and Secret as given here.
@@ -56,8 +58,8 @@ using Open Zaak as the example.
2. Then we need to allow Open Zaak to access Open Notificaties (for
authentication purposes, so we can then check its authorizations):
- a. Navigate to **API Autorisaties > Client credentials**
- b. Click **Client credential toevoegen**.
+ a. Navigate to **API Autorisaties > Autorisatiegegevens**
+ b. Click **Autorisatiegegeven toevoegen**.
c. Fill out the form:
- **Client ID**: *For example:* ``open-zaak``
@@ -121,4 +123,4 @@ All done!
.. _`documentation of Open Zaak`: https://open-zaak.readthedocs.io/en/latest/installation/config/openzaak_config.html#configure-notificaties-api
.. _`configuration of Open Zaak`: https://open-zaak.readthedocs.io/en/stable/installation/config/openzaak_config_cli.html#open-zaak-configuration
.. _`manual`: https://open-notificaties.readthedocs.io/en/stable/manual/subscriptions.html#aanmaken-abonnement
-.. _`API specification`: https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/open-zaak/open-notificaties/1.0.0/src/openapi.yaml#tag/notificaties
\ No newline at end of file
+.. _`API specification`: https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/open-zaak/open-notificaties/1.0.0/src/openapi.yaml#tag/notificaties
diff --git a/requirements/base.in b/requirements/base.in
index 624d7683..eb5f3665 100644
--- a/requirements/base.in
+++ b/requirements/base.in
@@ -4,6 +4,3 @@ open-api-framework
markdown
self-certifi
furl
-
-# API libraries
-gemma-zds-client
diff --git a/requirements/base.txt b/requirements/base.txt
index e7a8d9b4..0fd5c195 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -7,7 +7,10 @@
amqp==5.2.0
# via kombu
ape-pie==0.2.0
- # via zgw-consumers
+ # via
+ # commonground-api-common
+ # notifications-api-common
+ # zgw-consumers
asgiref==3.8.1
# via
# django
@@ -59,7 +62,7 @@ click-plugins==1.1.1
# via celery
click-repl==0.3.0
# via celery
-commonground-api-common==1.13.2
+commonground-api-common==2.1.0
# via open-api-framework
coreapi==2.3.3
# via commonground-api-common
@@ -201,11 +204,6 @@ furl==2.1.3
# via
# -r requirements/base.in
# ape-pie
-gemma-zds-client==1.0.1
- # via
- # -r requirements/base.in
- # commonground-api-common
- # notifications-api-common
glom==23.5.0
# via mozilla-django-oidc-db
humanize==4.10.0
@@ -242,7 +240,7 @@ mozilla-django-oidc==4.0.1
# via mozilla-django-oidc-db
mozilla-django-oidc-db==0.19.0
# via open-api-framework
-notifications-api-common==0.2.2
+notifications-api-common==0.3.1
# via commonground-api-common
open-api-framework==0.8.1
# via -r requirements/base.in
@@ -265,7 +263,6 @@ pycparser==2.22
pyjwt==2.9.0
# via
# commonground-api-common
- # gemma-zds-client
# zgw-consumers
pyopenssl==24.2.1
# via
@@ -289,7 +286,6 @@ pyyaml==6.0.2
# via
# drf-spectacular
# drf-yasg
- # gemma-zds-client
# oyaml
qrcode==7.4.2
# via django-two-factor-auth
@@ -305,10 +301,12 @@ requests==2.32.3
# commonground-api-common
# coreapi
# django-log-outgoing-requests
- # gemma-zds-client
# mozilla-django-oidc
# open-api-framework
+ # requests-mock
# zgw-consumers
+requests-mock==1.12.1
+ # via commonground-api-common
rpds-py==0.20.0
# via
# jsonschema
@@ -362,7 +360,8 @@ webencodings==0.5.1
# via bleach
wrapt==1.16.0
# via elastic-apm
-zgw-consumers==0.34.0
+zgw-consumers==0.35.1
# via
+ # commonground-api-common
# notifications-api-common
# open-api-framework
diff --git a/requirements/ci.txt b/requirements/ci.txt
index 27cb8488..093b6678 100644
--- a/requirements/ci.txt
+++ b/requirements/ci.txt
@@ -13,6 +13,8 @@ amqp==5.2.0
ape-pie==0.2.0
# via
# -r requirements/base.txt
+ # commonground-api-common
+ # notifications-api-common
# zgw-consumers
asgiref==3.8.1
# via
@@ -100,9 +102,10 @@ click-repl==0.3.0
# celery
codecov==2.1.13
# via -r requirements/ci.in
-commonground-api-common==1.13.2
+commonground-api-common[testutils]==2.1.0
# via
# -r requirements/base.txt
+ # -r requirements/test-tools.in
# open-api-framework
commonmark==0.9.1
# via recommonmark
@@ -163,6 +166,7 @@ django==4.2.15
# notifications-api-common
# open-api-framework
# zgw-consumers
+ # zgw-consumers-oas
django-admin-index==3.1.1
# via
# -r requirements/base.txt
@@ -324,7 +328,9 @@ face==20.1.1
factory-boy==3.2.1
# via -r requirements/test-tools.in
faker==13.15.1
- # via factory-boy
+ # via
+ # factory-boy
+ # zgw-consumers-oas
flake8==7.0.0
# via -r requirements/test-tools.in
flower==2.0.1
@@ -337,11 +343,6 @@ furl==2.1.3
# via
# -r requirements/base.txt
# ape-pie
-gemma-zds-client==1.0.1
- # via
- # -r requirements/base.txt
- # commonground-api-common
- # notifications-api-common
glom==23.5.0
# via
# -r requirements/base.txt
@@ -425,7 +426,7 @@ multidict==6.0.5
# via yarl
mypy-extensions==0.4.3
# via black
-notifications-api-common==0.2.2
+notifications-api-common==0.3.1
# via
# -r requirements/base.txt
# commonground-api-common
@@ -484,7 +485,6 @@ pyjwt==2.9.0
# via
# -r requirements/base.txt
# commonground-api-common
- # gemma-zds-client
# zgw-consumers
pyopenssl==24.2.1
# via
@@ -524,9 +524,9 @@ pyyaml==6.0.2
# -r requirements/base.txt
# drf-spectacular
# drf-yasg
- # gemma-zds-client
# oyaml
# vcrpy
+ # zgw-consumers-oas
qrcode==7.4.2
# via
# -r requirements/base.txt
@@ -550,14 +550,16 @@ requests==2.32.3
# commonground-api-common
# coreapi
# django-log-outgoing-requests
- # gemma-zds-client
# mozilla-django-oidc
# open-api-framework
# requests-mock
# sphinx
# zgw-consumers
requests-mock==1.12.1
- # via -r requirements/test-tools.in
+ # via
+ # -r requirements/base.txt
+ # -r requirements/test-tools.in
+ # commonground-api-common
rpds-py==0.20.0
# via
# -r requirements/base.txt
@@ -630,6 +632,7 @@ typing-extensions==4.12.2
# mozilla-django-oidc-db
# qrcode
# zgw-consumers
+ # zgw-consumers-oas
tzdata==2024.1
# via
# -r requirements/base.txt
@@ -683,8 +686,11 @@ wrapt==1.16.0
# vcrpy
yarl==1.9.4
# via vcrpy
-zgw-consumers==0.34.0
+zgw-consumers==0.35.1
# via
# -r requirements/base.txt
+ # commonground-api-common
# notifications-api-common
# open-api-framework
+zgw-consumers-oas==1.0.0
+ # via commonground-api-common
diff --git a/requirements/dev.txt b/requirements/dev.txt
index 91971b6f..5cad684b 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -13,6 +13,8 @@ amqp==5.2.0
ape-pie==0.2.0
# via
# -r requirements/base.txt
+ # commonground-api-common
+ # notifications-api-common
# zgw-consumers
asgiref==3.8.1
# via
@@ -103,9 +105,10 @@ click-repl==0.3.0
# via
# -r requirements/base.txt
# celery
-commonground-api-common==1.13.2
+commonground-api-common[testutils]==2.1.0
# via
# -r requirements/base.txt
+ # -r requirements/test-tools.in
# open-api-framework
commonmark==0.9.1
# via recommonmark
@@ -166,6 +169,7 @@ django==4.2.15
# notifications-api-common
# open-api-framework
# zgw-consumers
+ # zgw-consumers-oas
django-admin-index==3.1.1
# via
# -r requirements/base.txt
@@ -329,7 +333,9 @@ face==20.1.1
factory-boy==3.2.1
# via -r requirements/test-tools.in
faker==13.15.1
- # via factory-boy
+ # via
+ # factory-boy
+ # zgw-consumers-oas
flake8==7.0.0
# via -r requirements/test-tools.in
flower==2.0.1
@@ -342,11 +348,6 @@ furl==2.1.3
# via
# -r requirements/base.txt
# ape-pie
-gemma-zds-client==1.0.1
- # via
- # -r requirements/base.txt
- # commonground-api-common
- # notifications-api-common
gitdb==4.0.9
# via gitpython
gitpython==3.1.41
@@ -432,7 +433,7 @@ multidict==6.0.5
# via yarl
mypy-extensions==0.4.3
# via black
-notifications-api-common==0.2.2
+notifications-api-common==0.3.1
# via
# -r requirements/base.txt
# commonground-api-common
@@ -491,7 +492,6 @@ pyjwt==2.9.0
# via
# -r requirements/base.txt
# commonground-api-common
- # gemma-zds-client
# zgw-consumers
pyopenssl==24.2.1
# via
@@ -531,9 +531,9 @@ pyyaml==6.0.2
# -r requirements/base.txt
# drf-spectacular
# drf-yasg
- # gemma-zds-client
# oyaml
# vcrpy
+ # zgw-consumers-oas
qrcode==7.4.2
# via
# -r requirements/base.txt
@@ -556,14 +556,16 @@ requests==2.32.3
# commonground-api-common
# coreapi
# django-log-outgoing-requests
- # gemma-zds-client
# mozilla-django-oidc
# open-api-framework
# requests-mock
# sphinx
# zgw-consumers
requests-mock==1.12.1
- # via -r requirements/test-tools.in
+ # via
+ # -r requirements/base.txt
+ # -r requirements/test-tools.in
+ # commonground-api-common
rpds-py==0.20.0
# via
# -r requirements/base.txt
@@ -637,6 +639,7 @@ typing-extensions==4.12.2
# mozilla-django-oidc-db
# qrcode
# zgw-consumers
+ # zgw-consumers-oas
tzdata==2024.1
# via
# -r requirements/base.txt
@@ -692,11 +695,14 @@ wrapt==1.16.0
# vcrpy
yarl==1.9.4
# via vcrpy
-zgw-consumers==0.34.0
+zgw-consumers==0.35.1
# via
# -r requirements/base.txt
+ # commonground-api-common
# notifications-api-common
# open-api-framework
+zgw-consumers-oas==1.0.0
+ # via commonground-api-common
# The following packages are considered to be unsafe in a requirements file:
# pip
diff --git a/requirements/test-tools.in b/requirements/test-tools.in
index abf63be7..6601f1d8 100644
--- a/requirements/test-tools.in
+++ b/requirements/test-tools.in
@@ -17,3 +17,5 @@ recommonmark
Sphinx
sphinx-rtd-theme
sphinx-tabs
+
+commonground-api-common[testutils]>=2.0.1
diff --git a/requirements/testing.in b/requirements/testing.in
deleted file mode 100644
index 4c8ae87f..00000000
--- a/requirements/testing.in
+++ /dev/null
@@ -1,8 +0,0 @@
-# Shared between dev and Travis requirements to run our tests
-black
-coverage
-factory_boy
-freezegun
-isort
-requests-mock
-tblib
diff --git a/src/nrc/api/admin.py b/src/nrc/api/admin.py
index c1214fba..6f7455b2 100644
--- a/src/nrc/api/admin.py
+++ b/src/nrc/api/admin.py
@@ -2,8 +2,8 @@
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
+from vng_api_common.authorizations.utils import generate_jwt
from vng_api_common.models import JWTSecret
-from zds_client import ClientAuth
admin.site.unregister(JWTSecret)
@@ -16,13 +16,11 @@ class JWTSecretAdmin(admin.ModelAdmin):
readonly_fields = ("get_jwt",)
@admin.display(description="jwt")
- def get_jwt(self, obj):
+ def get_jwt(self, obj: JWTSecret):
if obj.identifier and obj.secret:
- auth = ClientAuth(obj.identifier, obj.secret)
- jwt = auth.credentials()["Authorization"]
return format_html(
'{val}
{hint}
', - val=jwt, + val=generate_jwt(obj.identifier, obj.secret, "", ""), hint=_("Gebruik het JWT-token nooit direct in een applicatie."), ) return "" diff --git a/src/nrc/api/tests/test_abonnement.py b/src/nrc/api/tests/test_abonnement.py index a9fc2e51..f7db67aa 100644 --- a/src/nrc/api/tests/test_abonnement.py +++ b/src/nrc/api/tests/test_abonnement.py @@ -9,10 +9,7 @@ from nrc.datamodel.tests.factories import AbonnementFactory, KanaalFactory -@override_settings( - LINK_FETCHER="vng_api_common.mocks.link_fetcher_200", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", -) +@override_settings(LINK_FETCHER="vng_api_common.mocks.link_fetcher_200") class AbonnementenTests(JWTAuthMixin, APITestCase): heeft_alle_autorisaties = True diff --git a/src/nrc/api/tests/test_kanaal.py b/src/nrc/api/tests/test_kanaal.py index e1612447..58250669 100644 --- a/src/nrc/api/tests/test_kanaal.py +++ b/src/nrc/api/tests/test_kanaal.py @@ -8,10 +8,7 @@ from nrc.datamodel.tests.factories import KanaalFactory -@override_settings( - LINK_FETCHER="vng_api_common.mocks.link_fetcher_200", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", -) +@override_settings(LINK_FETCHER="vng_api_common.mocks.link_fetcher_200") class KanalenTests(JWTAuthMixin, APITestCase): heeft_alle_autorisaties = True diff --git a/src/nrc/api/tests/test_notificatie.py b/src/nrc/api/tests/test_notificatie.py index 998855f4..0476b61b 100644 --- a/src/nrc/api/tests/test_notificatie.py +++ b/src/nrc/api/tests/test_notificatie.py @@ -25,7 +25,6 @@ @patch("nrc.api.serializers.deliver_message.delay") @override_settings( LINK_FETCHER="vng_api_common.mocks.link_fetcher_200", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", LOG_NOTIFICATIONS_IN_DB=True, ) class NotificatieTests(JWTAuthMixin, APITestCase): diff --git a/src/nrc/api/tests/test_validation.py b/src/nrc/api/tests/test_validation.py index b95d0cb6..d39171be 100644 --- a/src/nrc/api/tests/test_validation.py +++ b/src/nrc/api/tests/test_validation.py @@ -15,10 +15,7 @@ class AbonnementenValidationTests(JWTAuthMixin, APITestCase): heeft_alle_autorisaties = True - @override_settings( - LINK_FETCHER="vng_api_common.mocks.link_fetcher_404", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", - ) + @override_settings(LINK_FETCHER="vng_api_common.mocks.link_fetcher_404") def test_abonnementen_invalid_callback_url(self): KanaalFactory.create( naam="zaken", filters=["bron", "zaaktype", "vertrouwelijkheidaanduiding"] @@ -62,10 +59,7 @@ def test_abonnementen_invalid_callback_url(self): error = get_validation_errors(response, "nonFieldErrors") self.assertEqual(error["code"], "invalid-callback-url") - @override_settings( - LINK_FETCHER="vng_api_common.mocks.link_fetcher_404", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", - ) + @override_settings(LINK_FETCHER="vng_api_common.mocks.link_fetcher_404") def test_abonnementen_callback_url_accept_20x_status_codes(self): KanaalFactory.create( naam="zaken", filters=["bron", "zaaktype", "vertrouwelijkheidaanduiding"] @@ -113,7 +107,6 @@ def test_abonnementen_callback_url_accept_20x_status_codes(self): @override_settings( LINK_FETCHER="vng_api_common.mocks.link_fetcher_404", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", TEST_CALLBACK_AUTH=True, ) def test_abonnementen_callback_url_no_auth(self): @@ -159,7 +152,6 @@ def test_abonnementen_callback_url_no_auth(self): @override_settings( LINK_FETCHER="vng_api_common.mocks.link_fetcher_404", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", TEST_CALLBACK_AUTH=True, ) def test_webhooksite_whitelisted(self): @@ -189,10 +181,7 @@ def test_webhooksite_whitelisted(self): class KanalenValidationTests(JWTAuthMixin, APITestCase): heeft_alle_autorisaties = True - @override_settings( - LINK_FETCHER="vng_api_common.mocks.link_fetcher_404", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", - ) + @override_settings(LINK_FETCHER="vng_api_common.mocks.link_fetcher_404") def test_kanalen_invalid_documentatie_link_url(self): abonnement_create_url = get_operation_url("kanaal_create") @@ -212,10 +201,7 @@ class NotificatiesValidationTests(JWTAuthMixin, APITestCase): heeft_alle_autorisaties = True @freeze_time("2019-01-01T12:00:00Z") - @override_settings( - LINK_FETCHER="vng_api_common.mocks.link_fetcher_200", - ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient", - ) + @override_settings(LINK_FETCHER="vng_api_common.mocks.link_fetcher_200") @patch("jwt.api_jwt.PyJWT._validate_iat", return_value=None) def test_notificaties_aanmaakdatum_in_future_fails(self, mock_validate_iat): KanaalFactory.create(naam="zaken") diff --git a/src/nrc/conf/includes/base.py b/src/nrc/conf/includes/base.py index 01c47ac8..fc9f4fd2 100644 --- a/src/nrc/conf/includes/base.py +++ b/src/nrc/conf/includes/base.py @@ -27,7 +27,7 @@ MIDDLEWARE.insert( MIDDLEWARE.index("django.contrib.auth.middleware.AuthenticationMiddleware") + 1, - "vng_api_common.middleware.AuthMiddleware", + "vng_api_common.authorizations.middleware.AuthMiddleware", ) MIDDLEWARE = MIDDLEWARE + ["vng_api_common.middleware.APIVersionHeaderMiddleware"] diff --git a/src/nrc/config/authorization.py b/src/nrc/config/authorization.py index e15f6c58..0537f4c9 100644 --- a/src/nrc/config/authorization.py +++ b/src/nrc/config/authorization.py @@ -1,5 +1,7 @@ # SPDX-License-Identifier: EUPL-1.2 # Copyright (C) 2022 Dimpact +from typing import Iterable + from django.conf import settings from django.urls import reverse @@ -7,12 +9,29 @@ from django_setup_configuration.configuration import BaseConfigurationStep from django_setup_configuration.exceptions import SelfTestFailed from vng_api_common.authorizations.models import AuthorizationsConfig, ComponentTypes -from vng_api_common.models import APICredential, JWTSecret -from zds_client import ClientAuth +from vng_api_common.authorizations.utils import generate_jwt +from vng_api_common.models import JWTSecret +from zgw_consumers.models import Service from nrc.utils import build_absolute_url +def _generate_service_slug(existing_slugs: Iterable[str]) -> str: + default_slug = "authorization-api-service" + + if not existing_slugs or default_slug not in existing_slugs: + return default_slug + + slug = default_slug + count = 1 + + while slug in existing_slugs: + count += 1 + slug = f"{default_slug}-{count}" + + return slug + + class AuthorizationStep(BaseConfigurationStep): """ Open Notificaties uses Autorisaties API to check permissions of the clients. @@ -33,45 +52,57 @@ class AuthorizationStep(BaseConfigurationStep): enable_setting = "AUTHORIZATION_CONFIG_ENABLE" def is_configured(self) -> bool: - credential = APICredential.objects.filter( - api_root=settings.AUTORISATIES_API_ROOT - ) auth_config = AuthorizationsConfig.get_solo() + service = auth_config.authorizations_api_service - return credential.exists() and bool( - auth_config.api_root == settings.AUTORISATIES_API_ROOT - ) + if not service: + return False + + return service.api_root == settings.AUTORISATIES_API_ROOT def configure(self) -> None: # Step 1 auth_config = AuthorizationsConfig.get_solo() - if auth_config.api_root != settings.AUTORISATIES_API_ROOT: - auth_config.api_root = settings.AUTORISATIES_API_ROOT + + if auth_config.component != ComponentTypes.nrc: auth_config.component = ComponentTypes.nrc - auth_config.save(update_fields=["api_root", "component"]) # Step 2 organization = ( settings.OPENNOTIFICATIES_ORGANIZATION or settings.NOTIF_OPENZAAK_CLIENT_ID ) - APICredential.objects.update_or_create( + + service, _ = Service.objects.update_or_create( api_root=settings.AUTORISATIES_API_ROOT, - defaults={ - "label": "Open Zaak Autorisaties API", - "client_id": settings.NOTIF_OPENZAAK_CLIENT_ID, - "secret": settings.NOTIF_OPENZAAK_SECRET, - "user_id": settings.NOTIF_OPENZAAK_CLIENT_ID, - "user_representation": f"Open Notificaties {organization}", - }, + defaults=dict( + label="Open Zaak Autorisaties API", + client_id=settings.NOTIF_OPENZAAK_CLIENT_ID, + secret=settings.NOTIF_OPENZAAK_SECRET, + user_id=settings.NOTIF_OPENZAAK_CLIENT_ID, + user_representation=f"Open Notificaties {organization}", + ), ) + if not service.slug: + slugs = Service.objects.values_list("slug", flat=True) + service.slug = _generate_service_slug(slugs) + service.save(update_fields=("slug",)) + + auth_config.authorizations_api_service = service + auth_config.save(update_fields=("component", "authorizations_api_service")) + def test_configuration(self) -> None: """ This check depends on the configuration of permissions in Open Zaak """ client = AuthorizationsConfig.get_client() + + if not client: + raise SelfTestFailed("No service configured for the Autorisaties API") + try: - client.list("applicatie") + response: requests.Response = client.get("applicaties") + response.raise_for_status() except requests.RequestException as exc: raise SelfTestFailed( "Could not retrieve list of applications from Autorisaties API." @@ -115,14 +146,13 @@ def test_configuration(self): """ endpoint = reverse("kanaal-list", kwargs={"version": "1"}) full_url = build_absolute_url(endpoint, request=None) - auth = ClientAuth( - client_id=settings.OPENZAAK_NOTIF_CLIENT_ID, - secret=settings.OPENZAAK_NOTIF_SECRET, + token = generate_jwt( + settings.OPENZAAK_NOTIF_CLIENT_ID, settings.OPENZAAK_NOTIF_SECRET, "", "" ) try: response = requests.get( - full_url, headers={**auth.credentials(), "Accept": "application/json"} + full_url, headers={"Authorization": token, "Accept": "application/json"} ) response.raise_for_status() except requests.RequestException as exc: diff --git a/src/nrc/datamodel/management/commands/migrate_domains.py b/src/nrc/datamodel/management/commands/migrate_domains.py index 41143ef8..2ac7ca1f 100644 --- a/src/nrc/datamodel/management/commands/migrate_domains.py +++ b/src/nrc/datamodel/management/commands/migrate_domains.py @@ -25,11 +25,7 @@ def _base_mapping(variable: tuple) -> tuple: ) -BASE_MAPPING = ( - _base_mapping(("vng_api_common.APICredential", "api_root")) - + _base_mapping(("authorizations.AuthorizationsConfig", "api_root")) - + _base_mapping(("notifications.NotificationsConfig", "api_root")) -) +BASE_MAPPING = _base_mapping(("zgw_consumers.Service", "api_root")) MAPPING = BASE_MAPPING + ( ("datamodel.Kanaal", "documentatie_link", *ZRC), diff --git a/src/nrc/fixtures/default_admin_index.json b/src/nrc/fixtures/default_admin_index.json index 5f44c14c..82e61102 100644 --- a/src/nrc/fixtures/default_admin_index.json +++ b/src/nrc/fixtures/default_admin_index.json @@ -37,8 +37,8 @@ "applicatie" ], [ - "vng_api_common", - "apicredential" + "zgw_consumers", + "service" ], [ "vng_api_common", diff --git a/src/nrc/tests/commands/test_setup_configuration.py b/src/nrc/tests/commands/test_setup_configuration.py index 4c43b9e5..d087bdb9 100644 --- a/src/nrc/tests/commands/test_setup_configuration.py +++ b/src/nrc/tests/commands/test_setup_configuration.py @@ -11,9 +11,7 @@ from jwt import decode from rest_framework import status from vng_api_common.authorizations.models import AuthorizationsConfig -from zds_client.auth import ClientAuth -from zgw_consumers.constants import APITypes -from zgw_consumers.test import mock_service_oas_get +from vng_api_common.authorizations.utils import generate_jwt from nrc.config.authorization import AuthorizationStep, OpenZaakAuthStep from nrc.config.notification_retry import NotificationRetryConfigurationStep @@ -48,9 +46,6 @@ def test_setup_configuration(self, m): _uuid = uuid.uuid4() m.get("http://open-notificaties.example.com/", status_code=200) m.get("http://open-notificaties.example.com/api/v1/kanaal", json=[]) - mock_service_oas_get( - m, "https://oz.example.com/autorisaties/api/v1/", APITypes.ac - ) m.get( "https://oz.example.com/autorisaties/api/v1/applicaties", json={ @@ -96,7 +91,7 @@ def test_setup_configuration(self, m): ac_client = AuthorizationsConfig.get_client() self.assertIsNotNone(ac_client) - ac_client.list("applicatie") + ac_client.get("applicaties") create_call = m.last_request self.assertEqual( @@ -104,16 +99,18 @@ def test_setup_configuration(self, m): "https://oz.example.com/autorisaties/api/v1/applicaties", ) self.assertIn("Authorization", create_call.headers) + header_jwt = create_call.headers["Authorization"].split(" ")[1] decoded_jwt = decode(header_jwt, options={"verify_signature": False}) + self.assertEqual(decoded_jwt["client_id"], "notif-client-id") with self.subTest("Open Zaak can query Notification API"): - auth = ClientAuth("oz-client-id", "oz-secret") + token = generate_jwt("oz-client-id", "oz-secret", "", "") response = self.client.get( reverse("kanaal-list", kwargs={"version": 1}), - HTTP_AUTHORIZATION=auth.credentials()["Authorization"], + HTTP_AUTHORIZATION=token, ) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -122,9 +119,6 @@ def test_setup_configuration(self, m): def test_setup_configuration_selftest_fails(self, m): m.get("http://open-notificaties.example.com/", exc=requests.ConnectionError) m.get("http://open-notificaties.example.com/api/v1/kanaal", json=[]) - mock_service_oas_get( - m, "https://oz.example.com/autorisaties/api/v1/", APITypes.ac - ) m.get("https://oz.example.com/autorisaties/api/v1/applicaties", json=[]) with self.assertRaisesMessage( diff --git a/src/nrc/tests/config/test_authorization_configuration.py b/src/nrc/tests/config/test_authorization_configuration.py index 31507365..dfa4fd48 100644 --- a/src/nrc/tests/config/test_authorization_configuration.py +++ b/src/nrc/tests/config/test_authorization_configuration.py @@ -5,10 +5,8 @@ import requests import requests_mock from django_setup_configuration.exceptions import SelfTestFailed -from vng_api_common.authorizations.models import AuthorizationsConfig -from vng_api_common.models import APICredential, JWTSecret -from zgw_consumers.constants import APITypes -from zgw_consumers.test import mock_service_oas_get +from vng_api_common.authorizations.models import AuthorizationsConfig, ComponentTypes +from vng_api_common.models import JWTSecret from nrc.config.authorization import AuthorizationStep, OpenZaakAuthStep @@ -25,21 +23,21 @@ def test_configure(self): configuration.configure() config = AuthorizationsConfig.get_solo() - self.assertEqual(config.api_root, "https://oz.example.com/autorisaties/api/v1/") + service = config.authorizations_api_service - api_credentials = APICredential.objects.get( - api_root="https://oz.example.com/autorisaties/api/v1/" + self.assertEqual(config.component, ComponentTypes.nrc) + self.assertEqual( + service.api_root, "https://oz.example.com/autorisaties/api/v1/" ) - self.assertEqual(api_credentials.client_id, "notif-client-id") - self.assertEqual(api_credentials.secret, "notif-secret") + + self.assertEqual(service.client_id, "notif-client-id") + self.assertEqual(service.secret, "notif-secret") @requests_mock.Mocker() def test_selftest_ok(self, m): configuration = AuthorizationStep() configuration.configure() - mock_service_oas_get( - m, "https://oz.example.com/autorisaties/api/v1/", APITypes.ac - ) + m.get("https://oz.example.com/autorisaties/api/v1/applicaties", json=[]) configuration.test_configuration() @@ -52,12 +50,11 @@ def test_selftest_ok(self, m): def test_selftest_fail(self, m): configuration = AuthorizationStep() configuration.configure() - mock_service_oas_get( - m, "https://oz.example.com/autorisaties/api/v1/", APITypes.ac - ) - m.get("https://oz.example.com/autorisaties/api/v1/applicaties", json=[]) - configuration.test_configuration() + m.get("https://oz.example.com/autorisaties/api/v1/applicaties", status_code=403) + + with self.assertRaises(SelfTestFailed): + configuration.test_configuration() self.assertEqual( m.last_request.url, "https://oz.example.com/autorisaties/api/v1/applicaties" diff --git a/src/nrc/tests/test_handle_auth_notifications.py b/src/nrc/tests/test_handle_auth_notifications.py index 66eb4e0b..be923cf7 100644 --- a/src/nrc/tests/test_handle_auth_notifications.py +++ b/src/nrc/tests/test_handle_auth_notifications.py @@ -8,17 +8,21 @@ from vng_api_common.authorizations.models import Applicatie, AuthorizationsConfig from vng_api_common.constants import CommonResourceAction, VertrouwelijkheidsAanduiding from vng_api_common.tests import JWTAuthMixin, reverse -from zgw_consumers.constants import APITypes -from zgw_consumers.test import mock_service_oas_get +from zgw_consumers.test.factories import ServiceFactory class HandleAuthNotifTestCase(JWTAuthMixin, APITestCase): heeft_alle_autorisaties = True def test_handle_create_auth(self): + service = ServiceFactory(api_root="https://autorisaties-api.vng.cloud/api/v1") config = AuthorizationsConfig.get_solo() + + config.authorizations_api_service = service + config.save(update_fields=("authorizations_api_service",)) + uuid = _uuid.uuid4() - applicatie_url = f"{config.api_root}/applicaties/{uuid}" + applicatie_url = f"{service.api_root}/applicaties/{uuid}" webhook_url = reverse("notificaties-webhook") response_data = { @@ -45,7 +49,6 @@ def test_handle_create_auth(self): } with requests_mock.Mocker() as m: - mock_service_oas_get(m, url=config.api_root, service=APITypes.ac) m.get(applicatie_url, json=response_data) response = self.client.post(webhook_url, data) @@ -62,8 +65,14 @@ def test_handle_update_auth(self): client_ids=["id1"], label="before", heeft_alle_autorisaties=True ) uuid = applicatie.uuid + + service = ServiceFactory(api_root="https://autorisaties-api.vng.cloud/api/v1") + config = AuthorizationsConfig.get_solo() - applicatie_url = f"{config.api_root}/applicaties/{uuid}" + config.authorizations_api_service = service + config.save(update_fields=("authorizations_api_service",)) + + applicatie_url = f"{service.api_root}/applicaties/{uuid}" self.assertEqual(applicatie.autorisaties.count(), 0) @@ -115,8 +124,14 @@ def test_handle_delete_auth(self): client_ids=["id1"], label="for delete", heeft_alle_autorisaties=True ) uuid = applicatie.uuid + + service = ServiceFactory(api_root="https://autorisaties-api.vng.cloud/api/v1") + config = AuthorizationsConfig.get_solo() - applicatie_url = f"{config.api_root}/applicaties/{uuid}" + config.authorizations_api_service = service + config.save(update_fields=("authorizations_api_service",)) + + applicatie_url = f"{service.api_root}/applicaties/{uuid}" webhook_url = reverse( "notificaties-webhook", kwargs={"version": settings.REST_FRAMEWORK["DEFAULT_VERSION"]},