feat: WebSocket temps réel + Finance Workflow + corrections
- 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
This commit is contained in:
443
unionflow/docs/IMPLEMENTATION_SECURITE_PAGES.md
Normal file
443
unionflow/docs/IMPLEMENTATION_SECURITE_PAGES.md
Normal file
@@ -0,0 +1,443 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user