Easy_solution/docs/SSO_SLO_Documentation.md

6.1 KiB

Documentation SSO/SLO - EasyPortal & EasyCheck

Vue d'ensemble

Cette documentation décrit l'implémentation du Single Sign-On (SSO) et du Single Logout (SLO) entre deux applications Symfony :

  • EasyPortal : Serveur d'autorisation OAuth2 (Identity Provider)
  • EasyCheck : Application cliente OAuth2

Architecture

┌─────────────────┐                    ┌─────────────────┐
│   EasyPortal    │                    │   EasyCheck     │
│  (OAuth2 Server)│◄──────────────────►│ (OAuth2 Client) │
│                 │                    │                 │
│  - Authentifie  │                    │  - Utilise le   │
│  - Émet tokens  │                    │    token OAuth2 │
│  - Révoque      │                    │  - Valide token │
└─────────────────┘                    └─────────────────┘

Single Sign-On (SSO)

Principe

L'utilisateur s'authentifie une seule fois sur le portail et accède ensuite à toutes les applications sans re-saisir ses identifiants.

Flux d'authentification

1. Utilisateur → EasyCheck
   └─> Pas de session active

2. EasyCheck → Redirection vers EasyPortal
   └─> /authorize?client_id=...&redirect_uri=...

3. Utilisateur → Connexion sur EasyPortal
   └─> Login/Password ou session existante

4. EasyPortal → Redirection vers EasyCheck
   └─> /sso_check?code=AUTHORIZATION_CODE

5. EasyCheck → Échange du code contre un token
   └─> POST /token avec authorization_code
   └─> Reçoit access_token + refresh_token

6. EasyCheck → Création de session locale
   └─> Stockage du token en session
   └─> Utilisateur connecté

Single Logout (SLO)

Principe

Lorsqu'un utilisateur se déconnecte d'une application, il est automatiquement déconnecté de toutes les applications SSO via un appel API asynchrone, évitant les boucles de redirections.

Flux de déconnexion depuis EasyCheck

1. Utilisateur → Clic "Déconnexion" sur EasyCheck
   └─> GET /logout

2. Symfony → Invalide la session EasyCheck
   └─> Session détruite, cookies supprimés

3. LogoutSubscriber → Interception de l'événement
   └─> Détecte que ce n'est pas une déconnexion depuis le portail

4. EasyCheck → Redirection vers portail
   └─> GET https://portail.../sso_logout?from_easycheck=1

5. EasyPortal → Révocation des tokens OAuth2
   └─> Tous les access_token de l'utilisateur sont révoqués
   └─> Cookie logout_origin=easycheck créé (5 min)

6. EasyPortal → Redirection vers /logout
   └─> GET /logout

7. Symfony → Invalide la session EasyPortal
   └─> Session détruite

8. LogoutSubscriber → Redirection vers EasyCheck
   └─> GET https://check.../logout?from_portal=1

9. EasyCheck → Détecte from_portal=1
   └─> Invalide la session (si elle existe encore)
   └─> Redirection vers portail login

10. EasyPortal → Affichage page login
    └─> GET /login

11. Utilisateur se reconnecte → LoginSubscriber détecte cookie logout_origin
    └─> Redirection automatique vers EasyCheck /sso/login

Flux de déconnexion depuis EasyPortal

1. Utilisateur → Clic "Déconnexion" sur EasyPortal
   └─> GET /sso_logout

2. EasyPortal → Révocation des tokens OAuth2
   └─> Tous les access_token de l'utilisateur sont révoqués

3. EasyPortal → Redirection vers /logout
   └─> GET /logout

4. Symfony → Invalide la session EasyPortal
   └─> Session détruite

5. LogoutSubscriber → Redirection vers EasyCheck
   └─> GET https://check.../logout?from_portal=1

6. EasyCheck → Détecte from_portal=1
   └─> Invalide la session EasyCheck
   └─> Session détruite, cookies supprimés

7. EasyCheck → Redirection finale vers portail
   └─> GET https://portail.../login

Variables d'environnement

EasyCheck (.env)

# URL du serveur SSO (EasyPortal)
SSO_URL='https://portail.solutions-easy.moi'

# Configuration OAuth2
OAUTH_CLIENT_ID='easycheck-client-id'
OAUTH_CLIENT_SECRET='secret-key'

EasyPortal (.env)

# URL de l'application cliente (EasyCheck)
EASYCHECK_URL='https://check.solutions-easy.moi'

# Configuration OAuth2 Server
OAUTH_PRIVATE_KEY=%kernel.project_dir%/config/jwt/private.key
OAUTH_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.key
OAUTH_PASSPHRASE='passphrase'
OAUTH_ENCRYPTION_KEY='encryption-key'

Endpoints

EasyCheck - API Logout

Route : POST /api/logout

Description : Endpoint API pour invalider la session EasyCheck sans redirection. Utilisé par le portail lors du SLO.

Réponse :

{
  "success": true,
  "message": "Session invalidated successfully"
}

Comportement :

  • Invalide la session utilisateur
  • Ne redirige pas (contrairement à /logout)
  • Timeout de 2 secondes côté portail
  • Si l'appel échoue, le logout du portail continue quand même

Points importants

Sécurité

  1. CSRF désactivé sur logout : Les routes de logout utilisent enable_csrf: false car ce sont des liens GET simples
  2. Tokens révoqués : Lors du logout, tous les access_token de l'utilisateur sont révoqués côté portail
  3. Sessions invalidées : Les sessions PHP sont complètement détruites des deux côtés
  4. Cookies supprimés : Les cookies de session sont explicitement supprimés

Architecture

  1. Pas de boucles infinies : Utilisation de paramètres from_portal et from_easycheck pour éviter les boucles de redirections
  2. Déconnexion bidirectionnelle : Chaque application invalide la session de l'autre lors de la déconnexion
  3. Flux prévisible : Chaque déconnexion suit un chemin clair avec des paramètres explicites
  4. Retour automatique : Cookie logout_origin pour rediriger l'utilisateur vers l'application d'origine après reconnexion
  5. Single Logout complet : Les deux sessions (portail + EasyCheck) sont toujours invalidées, quelle que soit l'origine de la déconnexion