diff --git a/bin/Tiltfile b/bin/Tiltfile index e94e0a4..50e9199 100644 --- a/bin/Tiltfile +++ b/bin/Tiltfile @@ -59,6 +59,35 @@ cmd_button('Migrate db', text='Run database migration', ) +# Command to reset DB +reset_db = ''' +set -eu +# get k8s pod name from tilt resource name +POD_NAME="$(tilt get kubernetesdiscovery desk-backend -ojsonpath='{.status.pods[0].name}')" +kubectl -n desk exec "$POD_NAME" -- python manage.py flush --no-input +kubectl -n desk exec "$POD_NAME" -- python manage.py createsuperuser --username admin@example.com --password admin +''' +cmd_button('Reset DB', + argv=['sh', '-c', reset_db], + resource='desk-backend', + icon_name='developer_board', + text='Reset DB', +) + +# Command to create demo data +populate_people_with_demo_data = ''' +set -eu +# get k8s pod name from tilt resource name +POD_NAME="$(tilt get kubernetesdiscovery desk-backend -ojsonpath='{.status.pods[0].name}')" +kubectl -n desk exec "$POD_NAME" -- python manage.py create_demo --force +''' +cmd_button('Populate with demo data', + argv=['sh', '-c', populate_people_with_demo_data], + resource='desk-backend', + icon_name='developer_board', + text='Populate with demo data', +) + # Command to created domain/users/access from people to dimail populate_dimail_from_people = ''' set -eu diff --git a/docker-compose.yml b/docker-compose.yml index 6fd8a41..5b5d920 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -129,6 +129,8 @@ services: image: quay.io/keycloak/keycloak:20.0.1 volumes: - ./docker/auth/realm.json:/opt/keycloak/data/import/realm.json + extra_hosts: + - "host.docker.internal:host-gateway" command: - start-dev - --features=preview diff --git a/docker/auth/realm.json b/docker/auth/realm.json index c69add7..5966420 100644 --- a/docker/auth/realm.json +++ b/docker/auth/realm.json @@ -1652,8 +1652,130 @@ "enabledEventTypes": [], "adminEventsEnabled": false, "adminEventsDetailsEnabled": false, - "identityProviders": [], - "identityProviderMappers": [], + "identityProviders": [ + { + "alias": "oidc-people-local", + "displayName": "People OIDC (local)", + "internalId": "47aa6d7c-8ac5-4178-934e-66f78e510ee4", + "providerId": "oidc", + "enabled": true, + "updateProfileFirstLoginMode": "on", + "trustEmail": false, + "storeToken": false, + "addReadTokenRoleOnCreate": false, + "authenticateByDefault": false, + "linkOnly": false, + "firstBrokerLoginFlowAlias": "first broker login", + "config": { + "hideOnLoginPage": "false", + "userInfoUrl": "http://app-dev:8000/o/userinfo/", + "validateSignature": "true", + "acceptsPromptNoneForwardFromClient": "false", + "clientId": "people-idp", + "tokenUrl": "http://app-dev:8000/o/token/", + "uiLocales": "false", + "jwksUrl": "http://app-dev:8000/o/.well-known/jwks.json", + "backchannelSupported": "false", + "issuer": "http://app-dev:8000/o", + "useJwksUrl": "true", + "loginHint": "true", + "pkceEnabled": "true", + "pkceMethod": "S256", + "authorizationUrl": "http://localhost:8071/o/authorize/", + "clientAuthMethod": "client_secret_post", + "disableUserInfo": "false", + "syncMode": "IMPORT", + "clientSecret": "local-tests-only", + "passMaxAge": "false", + "defaultScope": "openid given_name usual_name email siret", + "allowedClockSkew": "0" + } + } + ], + "identityProviderMappers": [ + { + "id": "e55dc88c-7bb5-46fb-95ad-1df701a96282", + "name": "Sub", + "identityProviderAlias": "oidc-people-local", + "identityProviderMapper": "oidc-username-idp-mapper", + "config": { + "template": "${CLAIM.sub}", + "are.claim.values.regex": "false", + "claims": "[{\"key\":\"\",\"value\":\"\"}]", + "syncMode": "FORCE", + "attributes": "[]", + "target": "BROKER_ID" + } + }, + { + "id": "7e489676-8cba-49e4-aa1e-dcd1462d33f7", + "name": "given_name", + "identityProviderAlias": "oidc-people-local", + "identityProviderMapper": "hardcoded-attribute-idp-mapper", + "config": { + "claims": "[{\"key\":\"\",\"value\":\"\"}]", + "syncMode": "FORCE", + "are.claim.values.regex": "false", + "attributes": "[]", + "attribute": "firstName" + } + }, + { + "id": "30b6b3bc-5738-4936-bf88-c540b8805998", + "name": "usual_name", + "identityProviderAlias": "oidc-people-local", + "identityProviderMapper": "oidc-user-attribute-idp-mapper", + "config": { + "template": "${ALIAS}.${CLAIM.preferred_username}", + "are.claim.values.regex": "false", + "claims": "[{\"key\":\"profile\",\"value\":\"lastName\"}]", + "syncMode": "FORCE", + "claim": "profile", + "user.attribute": "lastName", + "attributes": "[]", + "target": "LOCAL" + } + }, + { + "id": "b67caa26-4571-4cfe-9c15-68e022645fc5", + "name": "Username", + "identityProviderAlias": "oidc-people-local", + "identityProviderMapper": "oidc-username-idp-mapper", + "config": { + "template": "${CLAIM.email | lowercase}", + "are.claim.values.regex": "false", + "claims": "[{\"key\":\"\",\"value\":\"\"}]", + "syncMode": "FORCE", + "attributes": "[]", + "target": "BROKER_USERNAME" + } + }, + { + "id": "4eef21ce-b5f7-4753-bd58-4e50eb2b5f31", + "name": "Email", + "identityProviderAlias": "oidc-people-local", + "identityProviderMapper": "oidc-user-attribute-idp-mapper", + "config": { + "are.claim.values.regex": "false", + "claims": "[{\"key\":\"\",\"value\":\"\"}]", + "syncMode": "FORCE", + "claim": "email", + "user.attribute": "email", + "attributes": "[]" + } + }, + { + "id": "084cdd0e-0794-4388-8474-84c9a7c1b9c8", + "name": "siret", + "identityProviderAlias": "oidc-people-local", + "identityProviderMapper": "oidc-user-attribute-idp-mapper", + "config": { + "syncMode": "FORCE", + "claim": "siret", + "user.attribute": "siret" + } + } + ], "components": { "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ { @@ -2195,7 +2317,7 @@ "authenticatorConfig": "review profile config", "authenticator": "idp-review-profile", "authenticatorFlow": false, - "requirement": "REQUIRED", + "requirement": "DISABLED", "priority": 10, "autheticatorFlow": false, "userSetupAllowed": false diff --git a/src/backend/demo/management/commands/create_demo.py b/src/backend/demo/management/commands/create_demo.py index a88ee15..5db565a 100755 --- a/src/backend/demo/management/commands/create_demo.py +++ b/src/backend/demo/management/commands/create_demo.py @@ -13,6 +13,7 @@ from django.core.management.base import BaseCommand, CommandError from django.utils.text import slugify from faker import Faker +from oauth2_provider.models import Application from treebeard.mp_tree import MP_Node from core import models @@ -133,6 +134,25 @@ class Timeit: return elapsed_time +def create_oidc_people_idp_client(): + """Configure the OIDC client for the People Identity Provider if missing.""" + try: + Application.objects.get(client_id="people-idp") + except Application.DoesNotExist: + application = Application( + client_id="people-idp", + client_secret="local-tests-only", + client_type=Application.CLIENT_CONFIDENTIAL, + authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE, + name="People Identity Provider", + algorithm=Application.RS256_ALGORITHM, + redirect_uris="http://localhost:8083/realms/people/broker/oidc-people-local/endpoint", + skip_authorization=True, + ) + application.clean() + application.save() + + def create_demo(stdout): # pylint: disable=too-many-locals """ Create a database with demo data for developers to work in a realistic environment. @@ -315,6 +335,10 @@ def create_demo(stdout): # pylint: disable=too-many-locals queue.flush() + # OIDC configuration + if settings.OAUTH2_PROVIDER.get("OIDC_ENABLED", False): + create_oidc_people_idp_client() + class Command(BaseCommand): """A management command to create a demo database.""" diff --git a/src/backend/demo/tests/test_commands_create_demo.py b/src/backend/demo/tests/test_commands_create_demo.py index 8b55dfe..3b93fcd 100644 --- a/src/backend/demo/tests/test_commands_create_demo.py +++ b/src/backend/demo/tests/test_commands_create_demo.py @@ -3,7 +3,6 @@ from unittest import mock from django.core.management import call_command -from django.test import override_settings import pytest @@ -11,6 +10,7 @@ from core import models from demo import defaults from mailbox_manager import models as mailbox_models +from people.settings import Base pytestmark = pytest.mark.django_db @@ -23,10 +23,13 @@ TEST_NB_OBJECTS = { } -@override_settings(DEBUG=True) @mock.patch.dict(defaults.NB_OBJECTS, TEST_NB_OBJECTS) -def test_commands_create_demo(): +def test_commands_create_demo(settings): """The create_demo management command should create objects as expected.""" + settings.DEBUG = True + settings.OAUTH2_PROVIDER["OIDC_ENABLED"] = True + settings.OAUTH2_PROVIDER["OIDC_RSA_PRIVATE_KEY"] = Base.generate_temporary_rsa_key() + call_command("create_demo") # Monique Test, Jeanne Test and Jean Something (quick fix for e2e) @@ -37,7 +40,7 @@ def test_commands_create_demo(): assert models.Team.objects.count() == TEST_NB_OBJECTS["teams"] assert models.TeamAccess.objects.count() >= TEST_NB_OBJECTS["teams"] - assert mailbox_models.MailDomain.objects.count() == TEST_NB_OBJECTS["domains"] + assert mailbox_models.MailDomain.objects.count() == TEST_NB_OBJECTS["domains"] + 1 # 3 domain access for each user with domain rights # 3 x 3 domain access for each user with both rights