208 lines
7.1 KiB
Markdown
208 lines
7.1 KiB
Markdown
# 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
|
|
└─> Paramètre redirect_app=easycheck propagé dans l'URL
|
|
|
|
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&redirect_app=easycheck
|
|
|
|
9. EasyCheck → Détecte from_portal=1
|
|
└─> Invalide la session (si elle existe encore)
|
|
└─> Redirection vers portail login avec redirect_app
|
|
|
|
10. EasyPortal → Affichage page login
|
|
└─> GET /login?redirect_app=easycheck
|
|
|
|
11. Utilisateur se reconnecte → LoginSubscriber détecte redirect_app=easycheck
|
|
└─> 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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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'
|
|
```
|
|
|
|
## Système de redirection multi-applications
|
|
|
|
### Paramètre `redirect_app`
|
|
|
|
Pour gérer plusieurs applications SSO (EasyCheck, EasyAudit, EasyMaintenance, etc.), le système utilise un **paramètre URL `redirect_app`** au lieu de cookies.
|
|
|
|
**Avantages** :
|
|
- ✅ Fonctionne avec plusieurs onglets ouverts simultanément
|
|
- ✅ Chaque onglet garde son contexte de déconnexion
|
|
- ✅ Pas de conflit entre applications
|
|
- ✅ Facilement extensible pour de nouvelles applications
|
|
|
|
**Fonctionnement** :
|
|
1. Lors de la déconnexion depuis une application, elle envoie `redirect_app=nom_app`
|
|
2. Ce paramètre est propagé dans toutes les redirections de logout
|
|
3. Il arrive sur la page `/login?redirect_app=nom_app`
|
|
4. Après reconnexion, l'utilisateur est redirigé vers l'application d'origine
|
|
|
|
**Configuration dans LoginSubscriber** :
|
|
```php
|
|
$appUrls = [
|
|
'easycheck' => $easycheckUrl . '/sso/login',
|
|
'easyaudit' => $easyauditUrl . '/sso/login',
|
|
'easymaintenance' => $easymaintenanceUrl . '/sso/login',
|
|
];
|
|
```
|
|
|
|
## Endpoints
|
|
|
|
### EasyCheck - API Logout
|
|
|
|
**Route** : `POST /api/logout`
|
|
|
|
**Description** : Endpoint API pour invalider la session EasyCheck sans redirection (non utilisé actuellement, prévu pour usage futur).
|
|
|
|
**Réponse** :
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Session invalidated successfully"
|
|
}
|
|
```
|
|
|
|
## 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 du paramètre `from_portal` 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** : Paramètre URL `redirect_app` pour rediriger l'utilisateur vers l'application d'origine après reconnexion
|
|
5. **Single Logout complet** : Toutes les sessions (portail + applications) sont toujours invalidées, quelle que soit l'origine de la déconnexion
|
|
6. **Multi-applications** : Support natif de plusieurs applications SSO sans conflit entre onglets |