diff --git a/CHANGELOG.md b/CHANGELOG.md index e18c2283c..e9664bdd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to ## [Unreleased] +### Added + +- 🧑‍💻(oidc) add ability to pull registration ID (e.g. SIRET) from OIDC #577 + ### Fixed - 🧑‍💻(user) fix the User.language infinite migration #611 diff --git a/docker/auth/realm.json b/docker/auth/realm.json index f14d9e837..05930cb95 100644 --- a/docker/auth/realm.json +++ b/docker/auth/realm.json @@ -59,7 +59,7 @@ "realmRoles": ["user"] }, { - "username": "marie", + "username": "e2e.marie", "email": "marie.varzy@gmail.com", "firstName": "Marie", "lastName": "Devarzy", @@ -70,7 +70,7 @@ "credentials": [ { "type": "password", - "value": "people" + "value": "password-e2e.marie" } ], "realmRoles": ["user"] diff --git a/src/backend/core/api/client/serializers.py b/src/backend/core/api/client/serializers.py index 9236b7833..df0410193 100644 --- a/src/backend/core/api/client/serializers.py +++ b/src/backend/core/api/client/serializers.py @@ -88,8 +88,8 @@ class UserOrganizationSerializer(serializers.ModelSerializer): class Meta: model = models.Organization - fields = ["id", "name"] - read_only_fields = ["id", "name"] + fields = ["id", "name", "registration_id_list"] + read_only_fields = ["id", "name", "registration_id_list"] class UserSerializer(DynamicFieldsModelSerializer): diff --git a/src/backend/core/tests/users/test_api_users_list.py b/src/backend/core/tests/users/test_api_users_list.py index 8520d7af6..023bae54e 100644 --- a/src/backend/core/tests/users/test_api_users_list.py +++ b/src/backend/core/tests/users/test_api_users_list.py @@ -4,6 +4,7 @@ from unittest import mock +import jq import pytest from rest_framework.status import ( HTTP_200_OK, @@ -77,7 +78,13 @@ def test_api_users_list_authenticated_response_content( response = client.get("/api/v1.0/users/") assert response.status_code == HTTP_200_OK - assert response.json() == { + json = response.json() + edited_json = ( + jq.compile(".results[] |= (.organization |= del(.registration_id_list))") + .input(json) + .first() + ) + assert edited_json == { "count": 2, "next": None, "previous": None, @@ -155,7 +162,13 @@ def test_api_users_authenticated_list_by_email(): response = client.get("/api/v1.0/users/?q=ool") assert response.status_code == HTTP_200_OK - assert response.json()["results"] == [ + json = response.json() + edited_json = ( + jq.compile(".results[] |= (.organization |= del(.registration_id_list))") + .input(json) + .first() + ) + assert edited_json["results"] == [ { "id": str(frank.id), "email": frank.email, @@ -228,7 +241,13 @@ def test_api_users_authenticated_list_by_name(): response = client.get("/api/v1.0/users/?q=oole") assert response.status_code == HTTP_200_OK - assert response.json()["results"] == [ + json = response.json() + edited_json = ( + jq.compile(".results[] |= (.organization |= del(.registration_id_list))") + .input(json) + .first() + ) + assert edited_json["results"] == [ { "id": str(frank.id), "email": frank.email, diff --git a/src/backend/core/tests/users/test_api_users_retrieve.py b/src/backend/core/tests/users/test_api_users_retrieve.py index 61621bee9..9bb217b14 100644 --- a/src/backend/core/tests/users/test_api_users_retrieve.py +++ b/src/backend/core/tests/users/test_api_users_retrieve.py @@ -61,6 +61,7 @@ def test_api_users_retrieve_me_authenticated(): "organization": { "id": str(user.organization.pk), "name": user.organization.name, + "registration_id_list": user.organization.registration_id_list, }, } diff --git a/src/backend/people/settings.py b/src/backend/people/settings.py index 6c1bb41bd..f1f5e7a34 100755 --- a/src/backend/people/settings.py +++ b/src/backend/people/settings.py @@ -639,6 +639,8 @@ class Development(Base): # this is a dev credentials for mail provisioning API MAIL_PROVISIONING_API_CREDENTIALS = "bGFfcmVnaWU6cGFzc3dvcmQ=" + OIDC_ORGANIZATION_REGISTRATION_ID_FIELD = "siret" + def __init__(self): """In dev, force installs needed for Swagger API.""" # pylint: disable=invalid-name diff --git a/src/backend/pyproject.toml b/src/backend/pyproject.toml index 9405a45e4..576262b61 100644 --- a/src/backend/pyproject.toml +++ b/src/backend/pyproject.toml @@ -66,6 +66,7 @@ dev = [ "drf-spectacular-sidecar==2024.12.1", "ipdb==0.13.13", "ipython==8.31.0", + "jq==1.8.0", "pyfakefs==5.7.3", "pylint-django==2.6.1", "pylint==3.3.2", diff --git a/src/frontend/apps/e2e/__tests__/app-desk/siret.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/siret.spec.ts new file mode 100644 index 000000000..b6b78779c --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-desk/siret.spec.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@playwright/test'; + +import { keyCloakSignIn } from './common'; + +test.beforeEach(async ({ page, browserName }) => { + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'marie'); +}); + +test.describe('OIDC interop with SIRET', () => { + test('it checks the SIRET is displayed in /me endpoint', async ({ page }) => { + const header = page.locator('header').first(); + await expect(header.getByAltText('Marianne Logo')).toBeVisible(); + + const response = await page.request.get( + 'http://localhost:8071/api/v1.0/users/me/', + ); + expect(response.ok()).toBeTruthy(); + expect(await response.json()).toMatchObject({ + organization: { registration_id_list: ['21580304000017'] }, + }); + }); +}); diff --git a/src/helm/env.d/dev/values.desk.yaml.gotmpl b/src/helm/env.d/dev/values.desk.yaml.gotmpl index fc5354233..eaac1d125 100644 --- a/src/helm/env.d/dev/values.desk.yaml.gotmpl +++ b/src/helm/env.d/dev/values.desk.yaml.gotmpl @@ -26,6 +26,7 @@ backend: OIDC_OP_TOKEN_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/token OIDC_OP_USER_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/userinfo OIDC_OP_LOGOUT_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/session/end + OIDC_ORGANIZATION_REGISTRATION_ID_FIELD: "siret" OIDC_RP_CLIENT_ID: secretKeyRef: name: backend