From 8fd1460010d93ee739488f4351776744764942c6 Mon Sep 17 00:00:00 2001 From: ikarius Date: Sat, 26 Oct 2024 08:05:57 +0200 Subject: [PATCH] Migration vers ProConnect (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ajout du bouton ProConnect officiel * oidc: redirection après callback d'identification OIDC * oidc: effacement des données de connexion avant logout OIDC En 2 phases : - effacement du token coté frontend - finalisation de la déconnexion coté backend * Ajout du bouton de déconnexion ProConnect * models: ajout du champ `sub_pc` pour ProConnect * oidc: modification de l'app - ajouts des routes pesonnalisées OIDC pour les redirections vers le front-end - modification de certaines portions de `mozilla-django-oidc` avec une vue custom * libs: ajout de `mozilla-django-oidc` Ainsi que sa configuration et la modification des routes pour permettre à la fois l'utilisation de ProConnect et d'Inclusion-Connect * Vérification de la déconnexion ProConnect En 2 étapes déjà gérées, mais cette fois-ci en véfifiant l'état du paramètre `state` passé par ProConnect (sécurité). * fix: ajout du backend d'identification par défaut Dans la configuration précédente, seule l'identification par OIDC était possible. Mais la partie admin de Django à besoin de l'identification par "modéle" (qui est celle par défaut). Les deux oexistent sereinement maintenant. * safir: récupération du code SAFIR Même si on n'en fait encore rien, le point de récupération de la donnée est identifié dans le code. * fix: modification d'un log en exception Résidu des tests, maintenant l'absence d'e-mail doit lever une exception. * Ajout d'une variable d'environnement pour identifier le backend OIDC On peut encore choisir entre Inclusion Connect et ProConnect via la var-env OIDC_AUTH_BACKEND (par défaut `proconnect`) * revue: typos * Vérification complémentaire de la validité du `sub` Moyen détourné de reporter la responsabilité de la validité des subs fournis vers ProConnect (ce qui est présentement le cas). * Ajout des assets ProConnect * Modification de la page de connexion L'affichage vers Inclusion Connect est toujours possible. * Modification des différentes pages mentionnant Inclusion Connect * fix: récupération de la var-env OIDC_AUTH_BACKEND Doit-être préfixée par 'VITE_' * fix: correction du `next_url` avec multiples paramètres * revue: corrections et typos --------- Co-authored-by: Gérald Gounot --- back/config/settings/base.py | 72 +++++- back/config/settings/test.py | 4 +- back/config/urls.py | 3 + back/dora/oidc/__init__.py | 124 +++++++++ back/dora/oidc/apps.py | 13 + back/dora/oidc/urls.py | 21 +- back/dora/oidc/views.py | 116 +++++++++ .../dora/users/migrations/0029_user_sub_pc.py | 17 ++ back/dora/users/models.py | 5 + back/requirements/base.txt | 1 + front/.env-example | 2 + .../assets/proconnect/bouton_proconnect.svg | 19 ++ .../lib/assets/proconnect/logo_proconnect.svg | 6 + .../components/specialized/pc-button.svelte | 36 +++ front/src/lib/env.ts | 2 + .../src/routes/_index/menu-mon-compte.svelte | 24 +- front/src/routes/auth/connexion/+page.svelte | 239 +++++++++++------- front/src/routes/auth/ic-callback/+page.ts | 2 + front/src/routes/auth/pc-callback/+page.ts | 2 + .../routes/auth/pc-callback/[token]/+page.ts | 16 ++ front/src/routes/auth/pc-logout/+page.ts | 8 + front/src/routes/mon-compte/+page.svelte | 40 ++- 22 files changed, 657 insertions(+), 115 deletions(-) create mode 100644 back/dora/oidc/apps.py create mode 100644 back/dora/users/migrations/0029_user_sub_pc.py create mode 100644 front/src/lib/assets/proconnect/bouton_proconnect.svg create mode 100644 front/src/lib/assets/proconnect/logo_proconnect.svg create mode 100644 front/src/lib/components/specialized/pc-button.svelte create mode 100644 front/src/routes/auth/pc-callback/+page.ts create mode 100644 front/src/routes/auth/pc-callback/[token]/+page.ts create mode 100644 front/src/routes/auth/pc-logout/+page.ts diff --git a/back/config/settings/base.py b/back/config/settings/base.py index e15f643af..093f45d50 100644 --- a/back/config/settings/base.py +++ b/back/config/settings/base.py @@ -26,6 +26,8 @@ INSTALLED_APPS = [ "django.contrib.gis", "django.contrib.auth", + # OIDC / ProConnect : doit être chargé après `django.contrib.auth` + "mozilla_django_oidc", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", @@ -64,8 +66,21 @@ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "csp.middleware.CSPMiddleware", + # Rafraichissement du token ProConnect + "mozilla_django_oidc.middleware.SessionRefresh", ] +# OIDC / ProConnect +AUTHENTICATION_BACKENDS = [ + # auth par défaut pour la partie admin : + "django.contrib.auth.backends.ModelBackend", + "dora.oidc.OIDCAuthenticationBackend", +] + +# Permet de garder le comportement d'identification "standard" (e-mail/password) +ACCOUNT_EMAIL_REQUIRED = True +ACCOUNT_AUTHENTICATION_METHOD = "email" + ROOT_URLCONF = "config.urls" TEMPLATES = [ @@ -287,7 +302,7 @@ # Modération : MATTERMOST_HOOK_KEY = os.getenv("MATTERMOST_HOOK_KEY") -# INCLUSION-CONNECT / PRO-CONNECT +# INCLUSION-CONNECT IC_ISSUER_ID = os.getenv("IC_ISSUER_ID") IC_AUTH_URL = os.getenv("IC_AUTH_URL") IC_TOKEN_URL = os.getenv("IC_TOKEN_URL") @@ -296,7 +311,59 @@ IC_CLIENT_ID = os.getenv("IC_CLIENT_ID") IC_CLIENT_SECRET = os.getenv("IC_CLIENT_SECRET") -# Recherches sauvagardées : +# OIDC / PROCONNECT +PC_CLIENT_ID = os.getenv("PC_CLIENT_ID") +PC_CLIENT_SECRET = os.getenv("PC_CLIENT_SECRET") +PC_DOMAIN = os.getenv("PC_DOMAIN", "fca.integ01.dev-agentconnect.fr") +PC_ISSUER = os.getenv("PC_ISSUER", f"{PC_DOMAIN}/api/v2") +PC_AUTHORIZE_PATH = os.getenv("PC_AUTHORIZE_PATH", "authorize") +PC_TOKEN_PATH = os.getenv("PC_TOKEN_PATH", "token") +PC_USERINFO_PATH = os.getenv("PC_USERINFO_PATH", "userinfo") + +# ProConnect à besoin de ce setting pour le logout +FRONTEND_URL = os.getenv("FRONTEND_URL") + +# mozilla_django_oidc: +OIDC_RP_CLIENT_ID = os.getenv("PC_CLIENT_ID") +OIDC_RP_CLIENT_SECRET = os.getenv("PC_CLIENT_SECRET") +OIDC_RP_SCOPES = "openid given_name usual_name email siret custom uid" + +# `mozilla_django_oidc` n'utilise pas de discovery / .well-known +# on définit donc chaque endpoint +OIDC_RP_SIGN_ALGO = "RS256" +OIDC_OP_JWKS_ENDPOINT = f"https://{PC_ISSUER}/jwks" +OIDC_OP_AUTHORIZATION_ENDPOINT = f"https://{PC_ISSUER}/authorize" +OIDC_OP_TOKEN_ENDPOINT = f"https://{PC_ISSUER}/token" +OIDC_OP_USER_ENDPOINT = f"https://{PC_ISSUER}/userinfo" +OIDC_OP_LOGOUT_ENDPOINT = f"https://{PC_ISSUER}/session/end" + +# Les paramètres suivants servent à adapter la configuration OIDC +# de `mozilla-django_oidc` pour pouvoir fonctionner dans le contexte +# spécifique à DORA et ProConnect. + +# OIDC : intervalle de rafraichissement du token (4h) +OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS = 4 * 60 * 60 + +# OIDC : nécessaire pour la gestion de la fin de session coté ProConnect +OIDC_STORE_ID_TOKEN = True +ALLOW_LOGOUT_GET_METHOD = True + +# obligatoire pour ProConnect: à passer en paramètre de requête supplémentaire +# lors de la première phase du flow OIDC +OIDC_AUTH_REQUEST_EXTRA_PARAMS = {"acr_values": "eidas1"} + +# OIDC : redirection vers le front DORA en cas de succès de l'identification +# necessaire pour la gestion de "l'URL suivant" (`next_url`) +LOGIN_REDIRECT_URL = "/oidc/logged_in/" + +# OIDC : redirection vers l'acceuil du front DORA pour la déconnexion +LOGOUT_REDIRECT_URL = FRONTEND_URL + +# OIDC : permet de préciser quelle est la class/vue en charge du callback dans le flow OIDC +# (essentiellement pour la gestion du `next_url`). +OIDC_CALLBACK_CLASS = "dora.oidc.views.CustomAuthorizationCallbackView" + +# Recherches sauvegardées : INCLUDES_DI_SERVICES_IN_SAVED_SEARCH_NOTIFICATIONS = ( os.getenv("INCLUDES_DI_SERVICES_IN_SAVED_SEARCH_NOTIFICATIONS") == "true" ) @@ -353,7 +420,6 @@ EMAIL_PORT = os.getenv("EMAIL_PORT") EMAIL_USE_TLS = True EMAIL_DOMAIN = os.getenv("EMAIL_DOMAIN") -FRONTEND_URL = os.getenv("FRONTEND_URL") SUPPORT_EMAIL = os.getenv("SUPPORT_EMAIL") SUPPORT_LINK = "https://aide.dora.inclusion.beta.gouv.fr" diff --git a/back/config/settings/test.py b/back/config/settings/test.py index 32efb52db..e5e353886 100644 --- a/back/config/settings/test.py +++ b/back/config/settings/test.py @@ -40,5 +40,7 @@ IC_TOKEN_URL = os.getenv("IC_TOKEN_URL", "https://whatever-oidc-token-url.com") AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME", "dora") SIB_ONBOARDING_LIST = os.getenv("SIB_ONBOARDING_LIST", "1") -SIB_ONBOARDING_PUTATIVE_MEMBER_LIST = os.getenv("SIB_ONBOARDING_PUTATIVE_MEMBER_LIST", "2") +SIB_ONBOARDING_PUTATIVE_MEMBER_LIST = os.getenv( + "SIB_ONBOARDING_PUTATIVE_MEMBER_LIST", "2" +) SIB_ONBOARDING_MEMBER_LIST = os.getenv("SIB_ONBOARDING_MEMBER_LIST", "3") diff --git a/back/config/urls.py b/back/config/urls.py index f76b534fe..b9e300856 100644 --- a/back/config/urls.py +++ b/back/config/urls.py @@ -112,7 +112,10 @@ urlpatterns = [ *private_api_patterns, *di_api_patterns, + # anciennes routes Inclusion-Connect (en attente de suppression) *oidc_patterns, + # nouvelles routes OIDC pour ProConnect + path("oidc/", include("mozilla_django_oidc.urls")), ] if settings.PROFILE: diff --git a/back/dora/oidc/__init__.py b/back/dora/oidc/__init__.py index b05f193d1..11f213db5 100644 --- a/back/dora/oidc/__init__.py +++ b/back/dora/oidc/__init__.py @@ -1,2 +1,126 @@ +from logging import getLogger + +import requests +from django.core.exceptions import SuspiciousOperation +from mozilla_django_oidc.auth import ( + OIDCAuthenticationBackend as MozillaOIDCAuthenticationBackend, +) +from rest_framework.authtoken.models import Token + +from dora.users.models import User + +logger = getLogger(__name__) + + class OIDCError(Exception): """Exception générique pour les erreurs OIDC""" + + +class OIDCAuthenticationBackend(MozillaOIDCAuthenticationBackend): + def get_userinfo(self, access_token, id_token, payload): + # Surcharge de la récupération des informations utilisateur: + # le décodage JSON du contenu JWT pose problème avec ProConnect + # qui le retourne en format binaire (content-type: application/jwt) + # d'où ce petit hack. + # Inspiré de : https://github.com/numerique-gouv/people/blob/b637774179d94cecb0ef2454d4762750a6a5e8c0/src/backend/core/authentication/backends.py#L47C1-L47C57 + user_response = requests.get( + self.OIDC_OP_USER_ENDPOINT, + headers={"Authorization": "Bearer {0}".format(access_token)}, + verify=self.get_settings("OIDC_VERIFY_SSL", True), + timeout=self.get_settings("OIDC_TIMEOUT", None), + proxies=self.get_settings("OIDC_PROXY", None), + ) + user_response.raise_for_status() + + try: + # cas où le type du token JWT est `application/json` + return user_response.json() + except requests.exceptions.JSONDecodeError: + # sinon, on présume qu'il s'agit d'un token JWT au format `application/jwt` (+...) + # comme c'est le cas pour ProConnect. + return self.verify_token(user_response.text) + + # Pas nécessaire de surcharger `get_or_create_user` puisque sur DORA, + # les utilisateurs ont un e-mail unique qui leur sert de `username`. + + def create_user(self, claims): + # on peut à la rigueur se passer de certains élements contenus dans les claims, + # mais pas de ceux-là : + email, sub = claims.get("email"), claims.get("sub") + if not email: + raise SuspiciousOperation( + "L'adresse e-mail n'est pas incluse dans les `claims`" + ) + + if not sub: + raise SuspiciousOperation( + "Le sujet (`sub`) n'est pas inclus dans les `claims`" + ) + + # L'utilisateur est créé sans mot de passe (aucune connexion à l'admin), + # et comme venant de ProConnect, on considère l'e-mail vérifié. + new_user = self.UserModel.objects.create_user( + email, + sub_pc=sub, + first_name=claims.get("given_name", "N/D"), + last_name=claims.get("usual_name", "N/D"), + is_valid=True, + ) + + # recupération du code SAFIR : + # même pour l'instant inutilisé, on pourra par la suite le passer au frontend + # pour rattachement direct à une agence France Travail + if custom := claims.get("custom"): + code_safir = custom.get("structureTravail") # noqa F481 + # TODO: une fois le code SAFIR récupéré, voir quoi en faire (redirection vers un rattachement) + + # compatibilité : + # durant la phase de migration vers ProConnect on ne replace *que* le fournisseur d'identité, + # et on ne touche pas aux mécanismes d'identification entre back et front. + self.get_or_create_drf_token(new_user) + + return new_user + + def update_user(self, user, claims): + # L'utilisateur peut déjà étre inscrit à IC, dans ce cas on réutilise la plupart + # des informations déjà connues + sub = claims.get("sub") + + if not sub: + raise SuspiciousOperation( + "Le sujet (`sub`) n'est pas inclu dans les `claims`" + ) + + if user.sub_pc and str(user.sub_pc) != sub: + raise SuspiciousOperation( + "Le sub enregistré est différent de celui fourni par ProConnect" + ) + + if not user.sub_pc: + # utilisateur existant, mais non-enregistré sur ProConnect + user.sub_pc = sub + user.save() + + return user + + def get_user(self, user_id): + if user := super().get_user(user_id): + self.get_or_create_drf_token(user) + return user + return None + + def get_or_create_drf_token(self, user_email): + # Pour être temporairement compatible, on crée un token d'identification DRF lié au nouvel utilisateur. + if not user_email: + raise SuspiciousOperation( + "Utilisateur non renseigné pour la création du token DRF" + ) + + user = User.objects.get(email=user_email) + + token, created = Token.objects.get_or_create(user=user) + + if created: + logger.info("Initialisation du token DRF pour l'utilisateur %s", user_email) + + return token diff --git a/back/dora/oidc/apps.py b/back/dora/oidc/apps.py new file mode 100644 index 000000000..44656c94a --- /dev/null +++ b/back/dora/oidc/apps.py @@ -0,0 +1,13 @@ +from django.apps import AppConfig + +""" +dora.oidc: + Gère les connexions OIDC-Connect via ProConnect. + Basée sur un provider custom de django-allauth. + Remplace l'ancien système de connexion à Inclusion-Connect à partir de novembre 2024. +""" + + +class OIDCConfig(AppConfig): + name = "dora.oidc" + verbose_name = "Gestion des connexions ProConnect" diff --git a/back/dora/oidc/urls.py b/back/dora/oidc/urls.py index 61c06b230..0f2eaaa1d 100644 --- a/back/dora/oidc/urls.py +++ b/back/dora/oidc/urls.py @@ -1,8 +1,9 @@ +import mozilla_django_oidc.urls # noqa: F401 from django.urls import path import dora.oidc.views as views -oidc_patterns = [ +inclusion_connect_patterns = [ path( "inclusion-connect-get-login-info/", views.inclusion_connect_get_login_info, @@ -20,3 +21,21 @@ views.inclusion_connect_authenticate, ), ] + +proconnect_patterns = [ + # les patterns internes pour le callback et le logout sont définis + # dans le fichier `urls.py` de mozilla_django_oidc + # redirection vers ProConnect pour la connexion + path("oidc/login/", views.oidc_login, name="oidc_login"), + # redirection une fois la connexion terminée + path("oidc/logged_in/", views.oidc_logged_in, name="oidc_logged_in"), + # preparation au logout : 2 étapes nécessaires + # l'une de déconnexion sur ProConnect, l'autre locale de destruction de la session active + path("oidc/pre_logout/", views.oidc_pre_logout, name="oidc_pre_logout"), + # la plupart des vues de `mozilla-django-oidc` sont paramètrables + # pas le logout + path("oidc/logout/", views.CustomLogoutView.as_view(), name="oidc_logout"), +] + + +oidc_patterns = inclusion_connect_patterns + proconnect_patterns diff --git a/back/dora/oidc/views.py b/back/dora/oidc/views.py index ddc0df37c..fe2b4352c 100644 --- a/back/dora/oidc/views.py +++ b/back/dora/oidc/views.py @@ -5,9 +5,17 @@ import requests from django.conf import settings from django.core.cache import cache +from django.core.exceptions import SuspiciousOperation from django.db import transaction +from django.http.response import HttpResponseRedirect +from django.urls import reverse from django.utils.crypto import get_random_string from furl import furl +from mozilla_django_oidc.views import ( + OIDCAuthenticationCallbackView, + OIDCLogoutView, + resolve_url, +) from rest_framework import permissions from rest_framework.authtoken.models import Token from rest_framework.decorators import api_view, permission_classes @@ -171,3 +179,111 @@ def inclusion_connect_authenticate(request): except requests.exceptions.RequestException as e: logging.exception(e) raise APIException("Erreur de communication avec le fournisseur d'identité") + + +# Migration vers ProConnect : +# En parallèle des différents endpoints OIDC inclusion-connect (gardés pour problème éventuel). + + +@api_view(["GET"]) +@permission_classes([permissions.AllowAny]) +def oidc_login(request): + # Simple redirection vers la page d'identification ProConnect (si pas identifié) + return HttpResponseRedirect( + redirect_to=reverse("oidc_authentication_init") + + f"?{request.META.get("QUERY_STRING")}" + ) + + +@api_view(["GET"]) +@permission_classes([permissions.AllowAny]) +def oidc_logged_in(request): + # étape indispensable pour le passage du token au frontend_state : + # malheuresement, cette étape est "zappée" si un paramètre `next` est passé lors de l'identification + # mozilla-django-oidc ne le prends pas en compte, il faut pour modifier la vue de callback et le redirect final + + # attention : l'utilisateur est toujours anonyme (a ce point il n'existe qu'un token DRF) + token = Token.objects.get(user_id=request.session["_auth_user_id"]) + + redirect_uri = f"{settings.FRONTEND_URL}/auth/pc-callback/{token}/" + + # gestion du next : + if request.GET.get("next"): + redirect_uri += "?" + request.GET.urlencode() + + # on redirige (pour l'instant) vers le front en faisant passer le token DRF + return HttpResponseRedirect(redirect_to=redirect_uri) + + +@api_view(["GET"]) +@permission_classes([permissions.AllowAny]) +def oidc_pre_logout(request): + # attention : le nom oidc_logout est pris par mozilla-django-oidc + # récupération du token stocké en session: + if oidc_token := request.session.get("oidc_id_token"): + # ProConnect nécessite un `state` pour vérifier la déconnexion effective + logout_state = get_random_string(32) + request.session["logout_state"] = logout_state + params = { + "id_token_hint": oidc_token, + "state": logout_state, + "post_logout_redirect_uri": request.build_absolute_uri( + reverse("oidc_logout") + ), + } + logout_url = furl(settings.OIDC_OP_LOGOUT_ENDPOINT, args=params) + return HttpResponseRedirect(redirect_to=logout_url.url) + + raise SuspiciousOperation("Tentative de déconnexion avec un token incorrect") + + +class CustomAuthorizationCallbackView(OIDCAuthenticationCallbackView): + """ + Callback OIDC : + Vue personnalisée basée en grande partie sur celle définie par `mozilla-django-oidc`, + pour la gestion du retour OIDC après identification. + + La gestion du `next_url` par la classe par défaut n'est pas satisfaisante dans le contexte de DORA, + la redirection vers le frontend nécessitant une étape supplémentaire pour l'enregistrement du token DRF. + Cette classe modifie la dernière redirection du flow pour y ajouter le paramètre d'URL suivant, + plutôt que d'effectuer une redirection directement vers ce paramètre. + + A noter qu'il est trés simple de modifier les différentes étapes du flow OIDC pour les adapter, + `mozilla-django-oidc` disposant d'une série de settings pour spécifier les classes de vue à utiliser + pour chaque étape OIDC (dans ce cas via le setting `OIDC_CALLBACK_CLASS`). + """ + + @property + def success_url(self): + # récupération du paramètre d'URL suivant stocké en session en début de flow OIDC + + next_url = self.request.session.get("oidc_login_next", None) + next_fieldname = self.get_settings("OIDC_REDIRECT_FIELD_NAME", "next") + + success_url = resolve_url(self.get_settings("LOGIN_REDIRECT_URL", "/")) + success_url += f"?{next_fieldname}={next_url}" if next_url else "" + + # redirection vers le front via `oidc/logged_in` + return success_url + + +class CustomLogoutView(OIDCLogoutView): + """ + Logout OIDC : + ProConnect effectue des vérifications avant de déconnecter l'utilisateur + sur sa plateforme. + Essentiellement en vérifiant la validité d'un `state` passé en paramètre + avant la destruction de la session. + Cette classe effectue simplement la vérification du `state` précédemment stocké + en session (voir `oidc/pre_logout`) et réutilise la classe de vue originale + de `mozilla-django-oidc`. + """ + + def post(self, request): + if logout_state := request.session.pop("logout_state", None): + if request.GET.get("state") != logout_state: + raise SuspiciousOperation("La vérification de la déconnexion a échoué") + else: + raise SuspiciousOperation("Vérification de la déconnexion impossible") + + return super().post(request) diff --git a/back/dora/users/migrations/0029_user_sub_pc.py b/back/dora/users/migrations/0029_user_sub_pc.py new file mode 100644 index 000000000..04be2d4ba --- /dev/null +++ b/back/dora/users/migrations/0029_user_sub_pc.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.14 on 2024-08-07 08:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("users", "0028_data_migration_cap_emploi"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="sub_pc", + field=models.UUIDField(null=True, verbose_name="Identifiant ProConnect"), + ), + ] diff --git a/back/dora/users/models.py b/back/dora/users/models.py index 68fb0ab46..dbac45eb3 100644 --- a/back/dora/users/models.py +++ b/back/dora/users/models.py @@ -65,9 +65,14 @@ def managers(self): class User(AbstractBaseUser): + # obsolète : sera remplacé par `sub_pc` pour ProConnect ic_id = models.UUIDField( verbose_name="Identifiant Inclusion Connect", null=True, blank=True ) + + # null possible en base ... pour l'instant + sub_pc = models.UUIDField(verbose_name="Identifiant ProConnect", null=True) + email = models.EmailField( verbose_name="email address", max_length=255, diff --git a/back/requirements/base.txt b/back/requirements/base.txt index 108064289..3afb3b056 100644 --- a/back/requirements/base.txt +++ b/back/requirements/base.txt @@ -8,6 +8,7 @@ django-storages[boto3]==1.14.4 djangorestframework-camel-case==1.4.2 djangorestframework-gis==1.1 djangorestframework==3.15.2 +mozilla-django-oidc==4.0.1 furl==2.1.3 hiredis==3.0.0 humanize==4.11.0 diff --git a/front/.env-example b/front/.env-example index 401ea3ee8..8751434c1 100644 --- a/front/.env-example +++ b/front/.env-example @@ -9,3 +9,5 @@ GITGUARDIAN_API_KEY= # Variables d'environnement publiques VITE_PUBLIC_MATOMO_CONTAINER_URL=# ex: "https:///js/container_.js" + +VITE_OIDC_AUTH_BACKEND=# proconnect | inclusionconnect diff --git a/front/src/lib/assets/proconnect/bouton_proconnect.svg b/front/src/lib/assets/proconnect/bouton_proconnect.svg new file mode 100644 index 000000000..a83a208c0 --- /dev/null +++ b/front/src/lib/assets/proconnect/bouton_proconnect.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/front/src/lib/assets/proconnect/logo_proconnect.svg b/front/src/lib/assets/proconnect/logo_proconnect.svg new file mode 100644 index 000000000..7e667b9c1 --- /dev/null +++ b/front/src/lib/assets/proconnect/logo_proconnect.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/front/src/lib/components/specialized/pc-button.svelte b/front/src/lib/components/specialized/pc-button.svelte new file mode 100644 index 000000000..c51538a0c --- /dev/null +++ b/front/src/lib/components/specialized/pc-button.svelte @@ -0,0 +1,36 @@ + + + diff --git a/front/src/lib/env.ts b/front/src/lib/env.ts index a21b2340b..32389100e 100644 --- a/front/src/lib/env.ts +++ b/front/src/lib/env.ts @@ -5,3 +5,5 @@ export const SENTRY_DSN = import.meta.env.VITE_SENTRY_DSN; export const CANONICAL_URL = import.meta.env.VITE_PUBLIC_CANONICAL_URL; export const METABASE_EMBED_URL = import.meta.env.VITE_METABASE_EMBED_URL; export const FLAG_STRIKING = import.meta.env.VITE_FLAG_STRIKING === "true"; +export const OIDC_AUTH_BACKEND = + import.meta.env.VITE_OIDC_AUTH_BACKEND || "proconnect"; diff --git a/front/src/routes/_index/menu-mon-compte.svelte b/front/src/routes/_index/menu-mon-compte.svelte index 181c105ae..d3f6ec3bb 100644 --- a/front/src/routes/_index/menu-mon-compte.svelte +++ b/front/src/routes/_index/menu-mon-compte.svelte @@ -1,6 +1,7 @@ @@ -23,14 +24,16 @@ Mes informations - + {#if OIDC_AUTH_BACKEND !== "proconnect"} + + {/if}
@@ -52,12 +55,23 @@

+

- Vous utilisez Inclusion Connect pour vous connecter à DORA. + {#if OIDC_AUTH_BACKEND === "proconnect"} + Vous utilisez ProConnect pour vous connecter à DORA. + {:else} + Vous utilisez Inclusion Connect pour vous connecter à DORA. + {/if}