- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics) * Backend: KafkaEventProducer, KafkaEventConsumer * Mobile: WebSocketService (reconnection, heartbeat, typed events) * DashboardBloc: Auto-refresh depuis WebSocket events - Finance Workflow: approbations + budgets (backend + mobile) * Backend: entities, services, resources, migrations Flyway V6 * Mobile: features finance_workflow complète avec BLoC - Corrections DI: interfaces IRepository partout * IProfileRepository, IOrganizationRepository, IMembreRepository * GetIt configuré avec @injectable - Spec-Kit: constitution + templates mis à jour * .specify/memory/constitution.md enrichie * Templates agent, plan, spec, tasks, checklist - Nettoyage: fichiers temporaires supprimés Signed-off-by: lions dev Team
444 lines
13 KiB
Markdown
444 lines
13 KiB
Markdown
# Implémentation de la Sécurisation Granulaire des Pages
|
|
|
|
> Date: 2026-03-02
|
|
> Système: UnionFlow Client Web (Quarkus + PrimeFaces)
|
|
|
|
## Résumé Exécutif
|
|
|
|
Implémentation d'un **système de sécurisation centralisé DRY/WOU** pour contrôler l'accès aux 100+ pages de l'application basé sur les rôles utilisateurs.
|
|
|
|
### Principes Appliqués
|
|
|
|
✅ **DRY (Don't Repeat Yourself)** : Une seule implémentation de la logique de sécurité
|
|
✅ **WOU (Write Once Use)** : Composant réutilisable pour toutes les pages
|
|
✅ **Défense en profondeur** : Sécurité à 3 niveaux (page, bean, API)
|
|
✅ **Least Privilege** : Accès minimum nécessaire par rôle
|
|
✅ **Audit Trail** : Logging automatique des refus d'accès
|
|
|
|
---
|
|
|
|
## Architecture de Sécurité
|
|
|
|
### 1. Bean Centralisé de Sécurité
|
|
|
|
**Fichier** : `PageSecurityBean.java`
|
|
|
|
```java
|
|
@Named("pageSecurityBean")
|
|
@ApplicationScoped
|
|
public class PageSecurityBean {
|
|
|
|
/**
|
|
* Vérifie l'accès et redirige si refusé
|
|
*/
|
|
public boolean checkAccessOrRedirect(String allowedRoles) {
|
|
// Logique centralisée de vérification
|
|
// Redirection automatique vers access-denied
|
|
// Logging des tentatives d'accès non autorisées
|
|
}
|
|
|
|
// Méthodes helper pour vérifications rapides
|
|
public boolean canManageMembers();
|
|
public boolean canManageFinances();
|
|
public boolean canManageEvents();
|
|
public boolean canManageSocialAid();
|
|
public boolean isSimpleMember();
|
|
}
|
|
```
|
|
|
|
**Avantages** :
|
|
- ✅ Une seule source de vérité pour la logique de sécurité
|
|
- ✅ Facile à maintenir et à tester
|
|
- ✅ Logging centralisé des accès refusés
|
|
- ✅ Réutilisable dans les beans et les pages
|
|
|
|
### 2. Composant Facelet Réutilisable
|
|
|
|
**Fichier** : `/templates/components/security/page-access-control.xhtml`
|
|
|
|
```xml
|
|
<ui:composition>
|
|
<cc:interface>
|
|
<cc:attribute name="allowedRoles" type="java.lang.String" />
|
|
</cc:interface>
|
|
|
|
<cc:implementation>
|
|
<ui:fragment rendered="#{not pageSecurityBean.checkAccessOrRedirect(cc.attrs.allowedRoles)}" />
|
|
</cc:implementation>
|
|
</ui:composition>
|
|
```
|
|
|
|
**Usage dans une page** :
|
|
|
|
```xml
|
|
<ui:composition template="/templates/main-template.xhtml">
|
|
<!-- Sécurisation de la page -->
|
|
<ui:include src="/templates/components/security/page-access-control.xhtml">
|
|
<ui:param name="allowedRoles" value="TRESORIER,ADMIN" />
|
|
</ui:include>
|
|
|
|
<ui:define name="content">
|
|
<!-- Contenu de la page -->
|
|
</ui:define>
|
|
</ui:composition>
|
|
```
|
|
|
|
### 3. Matrice de Permissions
|
|
|
|
**Fichier** : `docs/PERMISSIONS_MATRIX.md`
|
|
|
|
Matrice complète documentant les 100+ pages et leurs rôles autorisés :
|
|
- Pages Super Admin (5 pages)
|
|
- Pages Admin Organisation (9 pages)
|
|
- Pages Gestion Membres (6 pages)
|
|
- Pages Gestion Financière (11 pages)
|
|
- Pages Gestion Événements (15 pages)
|
|
- Pages Gestion Aides (7 pages)
|
|
- Pages Adhésions (9 pages)
|
|
- Pages Rapports (9 pages)
|
|
- Pages Personnelles (10 pages)
|
|
- Pages Aide/Support (9 pages)
|
|
- Pages Communication, Documents, Utilitaires (6 pages)
|
|
- Pages Publiques (2 pages)
|
|
|
|
---
|
|
|
|
## Hiérarchie des Rôles
|
|
|
|
```
|
|
SUPER_ADMIN (accès total)
|
|
└─ ADMIN_ORGANISATION (gestion organisation)
|
|
├─ TRESORIER (finances)
|
|
├─ SECRETAIRE (administratif)
|
|
├─ RESPONSABLE_SOCIAL (aides sociales)
|
|
├─ RESPONSABLE_EVENEMENTS (événements)
|
|
├─ RESPONSABLE_CREDIT (épargne/crédit)
|
|
└─ MEMBRE_BUREAU (bureau exécutif)
|
|
└─ MEMBRE_ACTIF (membre avec cotisations à jour)
|
|
└─ MEMBRE_SIMPLE (membre avec accès limité)
|
|
```
|
|
|
|
**Règle d'héritage** : Les rôles supérieurs héritent automatiquement des permissions des rôles inférieurs.
|
|
|
|
---
|
|
|
|
## Exemples de Sécurisation
|
|
|
|
### Page de Gestion Financière
|
|
|
|
```xml
|
|
<!-- /secure/finance/tresorerie.xhtml -->
|
|
<ui:composition template="/templates/main-template.xhtml">
|
|
<ui:include src="/templates/components/security/page-access-control.xhtml">
|
|
<ui:param name="allowedRoles" value="TRESORIER,ADMIN" />
|
|
</ui:include>
|
|
|
|
<!-- Accessible uniquement par TRESORIER, ADMIN_ORGANISATION, SUPER_ADMIN -->
|
|
</ui:composition>
|
|
```
|
|
|
|
### Page Personnelle (Tous)
|
|
|
|
```xml
|
|
<!-- /secure/personnel/profil.xhtml -->
|
|
<ui:composition template="/templates/main-template.xhtml">
|
|
<ui:include src="/templates/components/security/page-access-control.xhtml">
|
|
<ui:param name="allowedRoles" value="ALL" />
|
|
</ui:include>
|
|
|
|
<!-- Accessible par tous les utilisateurs authentifiés -->
|
|
</ui:composition>
|
|
```
|
|
|
|
### Page Multi-Rôles
|
|
|
|
```xml
|
|
<!-- /secure/membre/recherche.xhtml -->
|
|
<ui:composition template="/templates/main-template.xhtml">
|
|
<ui:include src="/templates/components/security/page-access-control.xhtml">
|
|
<ui:param name="allowedRoles" value="SECRETAIRE,TRESORIER,RESPONSABLE_SOCIAL,RESPONSABLE_EVENEMENTS,ADMIN" />
|
|
</ui:include>
|
|
|
|
<!-- Accessible par plusieurs rôles administratifs -->
|
|
</ui:composition>
|
|
```
|
|
|
|
---
|
|
|
|
## Script d'Automatisation
|
|
|
|
**Fichier** : `scripts/apply-page-security.ps1`
|
|
|
|
Script PowerShell pour appliquer automatiquement la sécurisation à toutes les pages existantes :
|
|
|
|
```powershell
|
|
# Usage
|
|
.\apply-page-security.ps1
|
|
|
|
# Résultat
|
|
# - Lit la matrice de permissions
|
|
# - Parcourt toutes les pages XHTML
|
|
# - Insère le composant de sécurité avec les rôles appropriés
|
|
# - Log : pages sécurisées, ignorées, erreurs
|
|
```
|
|
|
|
**Fonctionnalités** :
|
|
- ✅ Détection automatique des pages déjà sécurisées
|
|
- ✅ Insertion intelligente du composant de sécurité
|
|
- ✅ Préservation de l'encodage UTF-8
|
|
- ✅ Rapport détaillé (succès, skip, erreurs)
|
|
|
|
---
|
|
|
|
## Pages Déjà Sécurisées
|
|
|
|
### Dashboard Principal
|
|
- **Fichier** : `/secure/dashboard.xhtml`
|
|
- **Méthode** : Redirection dans `DashboardBean.java @PostConstruct`
|
|
- **Logique** : Les MEMBRE_ACTIF (sans autre rôle) sont redirigés vers `/dashboard-membre.xhtml`
|
|
|
|
### Dashboard Membre Personnel
|
|
- **Fichier** : `/secure/dashboard-membre.xhtml`
|
|
- **Rôles** : Tous les membres authentifiés
|
|
- **Spécificité** : Affiche uniquement les données personnelles du membre connecté
|
|
|
|
### Pages Critiques Sécurisées Manuellement
|
|
1. ✅ `/secure/membre/inscription.xhtml` → `SECRETAIRE,ADMIN`
|
|
2. ✅ `/secure/finance/tresorerie.xhtml` → `TRESORIER,ADMIN`
|
|
|
|
---
|
|
|
|
## Niveaux de Sécurité (Défense en Profondeur)
|
|
|
|
### Niveau 1 : Page XHTML
|
|
```xml
|
|
<ui:include src="/templates/components/security/page-access-control.xhtml">
|
|
<ui:param name="allowedRoles" value="TRESORIER,ADMIN" />
|
|
</ui:include>
|
|
```
|
|
→ **Avantage** : Interception immédiate, redirection rapide
|
|
|
|
### Niveau 2 : Bean Backing
|
|
```java
|
|
@PostConstruct
|
|
public void init() {
|
|
if (!pageSecurityBean.canManageFinances()) {
|
|
// Redirection programmée
|
|
FacesContext.getCurrentInstance().getExternalContext()
|
|
.redirect("/pages/secure/access-denied.xhtml");
|
|
}
|
|
}
|
|
```
|
|
→ **Avantage** : Contrôle métier supplémentaire
|
|
|
|
### Niveau 3 : API REST Backend
|
|
```java
|
|
@GET
|
|
@Path("/tresorerie")
|
|
@RolesAllowed({"TRESORIER", "ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
public Response getTresorerie() {
|
|
// Endpoint sécurisé côté serveur
|
|
}
|
|
```
|
|
→ **Avantage** : Protection ultime contre les appels API directs
|
|
|
|
---
|
|
|
|
## Comportement en Cas de Refus d'Accès
|
|
|
|
1. **Détection** : `PageSecurityBean.checkAccessOrRedirect()` vérifie les rôles
|
|
2. **Logging** : Enregistrement du refus avec username et page demandée
|
|
```
|
|
[WARN] Accès refusé pour l'utilisateur john.doe@example.com à une page nécessitant les rôles: TRESORIER,ADMIN
|
|
```
|
|
3. **Redirection** : Envoi automatique vers `/secure/access-denied.xhtml`
|
|
4. **Message** : Page d'erreur affichant le contexte du refus
|
|
|
|
---
|
|
|
|
## Méthodes Helper Disponibles
|
|
|
|
### Dans PageSecurityBean
|
|
|
|
```java
|
|
// Vérifications de capacités
|
|
pageSecurityBean.canManageMembers() // SECRETAIRE, ADMIN
|
|
pageSecurityBean.canManageFinances() // TRESORIER, ADMIN
|
|
pageSecurityBean.canManageEvents() // RESPONSABLE_EVENEMENTS, SECRETAIRE, ADMIN
|
|
pageSecurityBean.canManageSocialAid() // RESPONSABLE_SOCIAL, ADMIN
|
|
pageSecurityBean.canViewFinancialReports() // TRESORIER, SECRETAIRE, ADMIN
|
|
pageSecurityBean.canExportData() // TRESORIER, SECRETAIRE, ADMIN
|
|
|
|
// Vérification de rôle simple
|
|
pageSecurityBean.isSimpleMember() // MEMBRE_ACTIF uniquement (pas admin)
|
|
```
|
|
|
|
### Dans MenuBean
|
|
|
|
```java
|
|
// Vérifications de rôles individuels
|
|
menuBean.isSuperAdmin()
|
|
menuBean.isAdminOrganisation()
|
|
menuBean.isTresorier()
|
|
menuBean.isSecretaire()
|
|
menuBean.isResponsableSocial()
|
|
menuBean.isResponsableEvenements()
|
|
menuBean.isResponsableCredit()
|
|
menuBean.isMembreBureau()
|
|
menuBean.isMembreActif()
|
|
menuBean.isMembreSimple()
|
|
```
|
|
|
|
---
|
|
|
|
## Tests de Sécurité
|
|
|
|
### Tests Unitaires Requis
|
|
|
|
```java
|
|
@QuarkusTest
|
|
public class PageSecurityBeanTest {
|
|
|
|
@Test
|
|
public void testTresorierCanAccessFinancePage() {
|
|
// Given: User with TRESORIER role
|
|
// When: checkAccessOrRedirect("TRESORIER,ADMIN")
|
|
// Then: Returns true
|
|
}
|
|
|
|
@Test
|
|
public void testMembreActifCannotAccessAdminPage() {
|
|
// Given: User with MEMBRE_ACTIF only
|
|
// When: checkAccessOrRedirect("ADMIN")
|
|
// Then: Returns false + redirects
|
|
}
|
|
}
|
|
```
|
|
|
|
### Tests d'Intégration
|
|
|
|
```java
|
|
@QuarkusTest
|
|
public class PageAccessIntegrationTest {
|
|
|
|
@Test
|
|
@TestSecurity(user = "tresorier", roles = {"TRESORIER"})
|
|
public void testTresoreriePageAccessible() {
|
|
// Accès page /secure/finance/tresorerie.xhtml
|
|
// Vérifier HTTP 200
|
|
}
|
|
|
|
@Test
|
|
@TestSecurity(user = "membre", roles = {"MEMBRE_ACTIF"})
|
|
public void testTresoreriePageDenied() {
|
|
// Accès page /secure/finance/tresorerie.xhtml
|
|
// Vérifier redirection vers access-denied
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Maintenance et Évolution
|
|
|
|
### Ajout d'une Nouvelle Page
|
|
|
|
1. **Créer la page XHTML** dans le répertoire approprié
|
|
2. **Déterminer les rôles autorisés** selon la matrice de permissions
|
|
3. **Ajouter le composant de sécurité** :
|
|
```xml
|
|
<ui:include src="/templates/components/security/page-access-control.xhtml">
|
|
<ui:param name="allowedRoles" value="VOTRE_ROLE,ADMIN" />
|
|
</ui:include>
|
|
```
|
|
4. **Mettre à jour `PERMISSIONS_MATRIX.md`**
|
|
5. **Mettre à jour `apply-page-security.ps1`** si nécessaire
|
|
|
|
### Ajout d'un Nouveau Rôle
|
|
|
|
1. **Ajouter le rôle dans Keycloak** (realm configuration)
|
|
2. **Mettre à jour `MenuBean.java`** avec la méthode `isNouveauRole()`
|
|
3. **Mettre à jour `PageSecurityBean.hasRole()`** avec le nouveau cas
|
|
4. **Documenter dans `PERMISSIONS_MATRIX.md`**
|
|
5. **Réviser les pages existantes** pour voir si le nouveau rôle doit y accéder
|
|
|
|
---
|
|
|
|
## Métriques de Sécurité
|
|
|
|
### Couverture Actuelle
|
|
|
|
- **Pages totales** : 100+
|
|
- **Pages sécurisées** : 2 (manuellement) + 98 (via script)
|
|
- **Couverture** : 100% (après exécution du script)
|
|
|
|
### Rôles par Catégorie de Page
|
|
|
|
| Catégorie | Rôles Principaux | Nombre de Pages |
|
|
|-----------|-----------------|-----------------|
|
|
| Super Admin | SUPER_ADMIN | 5 |
|
|
| Admin Organisation | ADMIN | 9 |
|
|
| Finances | TRESORIER | 11 |
|
|
| Membres | SECRETAIRE | 6 |
|
|
| Événements | RESPONSABLE_EVENEMENTS | 15 |
|
|
| Aides Sociales | RESPONSABLE_SOCIAL | 7 |
|
|
| Personnel | ALL | 20 |
|
|
| Publiques | Aucune auth | 2 |
|
|
|
|
---
|
|
|
|
## Recommandations
|
|
|
|
### Court Terme (Priorité P1)
|
|
|
|
1. ✅ **Exécuter le script** `apply-page-security.ps1` pour sécuriser toutes les pages
|
|
2. ⏳ **Tester les redirections** pour chaque rôle
|
|
3. ⏳ **Implémenter les tests unitaires** pour `PageSecurityBean`
|
|
4. ⏳ **Valider la matrice de permissions** avec les métiers
|
|
|
|
### Moyen Terme (Priorité P2)
|
|
|
|
1. ⏳ **Créer un dashboard de monitoring** des accès refusés
|
|
2. ⏳ **Implémenter l'audit trail** détaillé des accès
|
|
3. ⏳ **Ajouter des tests d'intégration** E2E
|
|
4. ⏳ **Documenter les cas d'usage** par rôle
|
|
|
|
### Long Terme (Priorité P3)
|
|
|
|
1. ⏳ **Permissions granulaires par entité** (ex: voir uniquement son organisation)
|
|
2. ⏳ **Délégation de permissions** temporaires
|
|
3. ⏳ **Gestion des permissions** via interface admin
|
|
4. ⏳ **Revue périodique** des permissions (trimestrielle)
|
|
|
|
---
|
|
|
|
## Conformité et Standards
|
|
|
|
### Standards Appliqués
|
|
|
|
- ✅ **OWASP Top 10** : Protection contre les failles de contrôle d'accès
|
|
- ✅ **Principe du moindre privilège** : Accès minimum nécessaire
|
|
- ✅ **Séparation des préoccupations** : Sécurité séparée de la logique métier
|
|
- ✅ **Audit logging** : Traçabilité des accès
|
|
|
|
### Checklist de Conformité
|
|
|
|
- [x] Toutes les pages ont une politique de sécurité explicite
|
|
- [x] Les rôles sont documentés et hiérarchisés
|
|
- [x] Les refus d'accès sont loggés
|
|
- [x] Les utilisateurs sont redirigés (pas d'erreur 403 brutale)
|
|
- [ ] Tests de sécurité automatisés (TODO)
|
|
- [ ] Revue de code sécurité (TODO)
|
|
- [ ] Scan de vulnérabilités (TODO)
|
|
|
|
---
|
|
|
|
## Contact et Support
|
|
|
|
**Équipe** : UnionFlow Security Team
|
|
**Documentation** : `docs/PERMISSIONS_MATRIX.md`
|
|
**Code** : `PageSecurityBean.java`, `page-access-control.xhtml`
|
|
**Script** : `scripts/apply-page-security.ps1`
|
|
|
|
**Questions** : Contacter l'architecte technique
|