Version stable - Authentifiaction Ok + Dashboard SuperAdmin

This commit is contained in:
DahoudG
2025-09-19 18:34:04 +00:00
parent 3f2398a55d
commit a1214bc116
4 changed files with 899 additions and 395 deletions

208
test_superadmin_role.py Normal file
View File

@@ -0,0 +1,208 @@
#!/usr/bin/env python3
"""
Test du mapping du rôle SUPER_ADMINISTRATEUR
"""
import requests
import json
import base64
def test_superadmin_role():
base_url = "http://localhost:8180"
print("🧪 Test du rôle SUPER_ADMINISTRATEUR")
print("=" * 60)
print()
# Test avec superadmin@unionflow.com
email_username = "superadmin@unionflow.com"
password = "SuperAdmin123!"
print(f"🔐 Authentification de {email_username}")
data = {
"username": email_username,
"password": password,
"grant_type": "password",
"client_id": "unionflow-mobile"
}
try:
response = requests.post(
f"{base_url}/realms/unionflow/protocol/openid-connect/token",
data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
print(f"📊 Status: {response.status_code}")
if response.status_code == 200:
token_data = response.json()
if "access_token" in token_data:
print("✅ AUTHENTIFICATION RÉUSSIE !")
# Décoder le token pour voir les rôles
access_token = token_data['access_token']
# Décoder le payload du JWT
token_parts = access_token.split('.')
if len(token_parts) >= 2:
# Ajouter du padding si nécessaire
payload = token_parts[1]
payload += '=' * (4 - len(payload) % 4)
decoded = base64.b64decode(payload)
token_info = json.loads(decoded)
print()
print("🎫 INFORMATIONS DU TOKEN :")
print(f" 👤 Utilisateur: {token_info.get('preferred_username', 'N/A')}")
print(f" 📧 Email: {token_info.get('email', 'N/A')}")
print(f" 👨‍💼 Nom: {token_info.get('name', 'N/A')}")
# Extraire les rôles
roles = []
if 'realm_access' in token_info and 'roles' in token_info['realm_access']:
all_roles = token_info['realm_access']['roles']
# Filtrer les rôles système
roles = [r for r in all_roles if not r.startswith('default-') and r not in ['offline_access', 'uma_authorization']]
print()
print("🎭 RÔLES KEYCLOAK EXTRAITS :")
for role in roles:
if role == 'SUPER_ADMINISTRATEUR':
print(f"{role} (SUPER ADMIN - ACCÈS COMPLET)")
else:
print(f"{role}")
print()
print("🎯 MAPPING VERS L'APPLICATION MOBILE :")
if 'SUPER_ADMINISTRATEUR' in roles:
print(" ✅ Rôle mappé: UserRole.superAdmin")
print(" ✅ Dashboard: SuperAdminDashboard")
print(" ✅ Navigation: Command Center")
print(" ✅ Permissions: ACCÈS COMPLET SYSTÈME")
print()
print("🚀 FONCTIONNALITÉS DISPONIBLES :")
print(" • Vue globale multi-organisations")
print(" • Métriques système en temps réel")
print(" • Outils d'administration avancés")
print(" • Monitoring et analytics")
print(" • Gestion des utilisateurs globale")
print(" • Configuration système")
print(" • Sécurité et audit")
print(" • Sauvegarde et maintenance")
print()
print("📱 ONGLETS DU DASHBOARD :")
print(" 1. Vue Globale - Métriques système")
print(" 2. Organisations - Gestion multi-org")
print(" 3. Système - Monitoring technique")
print(" 4. Analytics - Rapports avancés")
return True
else:
print(" ❌ Rôle SUPER_ADMINISTRATEUR non trouvé")
print(" ⚠️ L'utilisateur sera mappé comme visiteur")
return False
else:
print("❌ Token manquant dans la réponse")
else:
print("❌ Authentification échouée")
print(f"Response: {response.text}")
return False
except Exception as e:
print(f"❌ Erreur: {e}")
return False
def test_all_roles():
"""Teste tous les comptes avec leurs rôles"""
base_url = "http://localhost:8180"
print()
print("=" * 60)
print("🧪 TEST DE TOUS LES RÔLES UNIONFLOW")
print("=" * 60)
print()
users = [
("superadmin@unionflow.com", "SuperAdmin123!", "SUPER_ADMINISTRATEUR"),
("marie.active@unionflow.com", "Marie123!", "MEMBRE_ACTIF"),
("jean.simple@unionflow.com", "Jean123!", "MEMBRE_SIMPLE"),
("tech.lead@unionflow.com", "TechLead123!", "RESPONSABLE_TECHNIQUE"),
("rh.manager@unionflow.com", "RhManager123!", "RESPONSABLE_MEMBRES"),
]
for email, password, expected_role in users:
print(f"🔐 Test de {email} (attendu: {expected_role})")
data = {
"username": email,
"password": password,
"grant_type": "password",
"client_id": "unionflow-mobile"
}
try:
response = requests.post(
f"{base_url}/realms/unionflow/protocol/openid-connect/token",
data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
if response.status_code == 200:
token_data = response.json()
access_token = token_data['access_token']
# Décoder le token
token_parts = access_token.split('.')
payload = token_parts[1]
payload += '=' * (4 - len(payload) % 4)
decoded = base64.b64decode(payload)
token_info = json.loads(decoded)
# Extraire les rôles
roles = []
if 'realm_access' in token_info and 'roles' in token_info['realm_access']:
all_roles = token_info['realm_access']['roles']
roles = [r for r in all_roles if not r.startswith('default-') and r not in ['offline_access', 'uma_authorization']]
if expected_role in roles:
print(f" ✅ Rôle {expected_role} trouvé")
else:
print(f" ❌ Rôle {expected_role} manquant. Rôles trouvés: {roles}")
else:
print(f" ❌ Authentification échouée: {response.status_code}")
except Exception as e:
print(f" ❌ Erreur: {e}")
print()
if __name__ == "__main__":
success = test_superadmin_role()
if success:
print()
print("=" * 60)
print("🎉 SUPER ADMINISTRATEUR CONFIGURÉ AVEC SUCCÈS !")
print("=" * 60)
print()
print("📱 VOTRE APPLICATION MOBILE AFFICHERA :")
print(" • Dashboard Super Admin complet")
print(" • Navigation Command Center")
print(" • Toutes les fonctionnalités administratives")
print()
print("🚀 Testez maintenant sur votre Samsung avec :")
print(" Username: superadmin@unionflow.com")
print(" Password: SuperAdmin123!")
else:
print()
print("⚠️ Problème de configuration détecté")
print("Vérifiez que le rôle SUPER_ADMINISTRATEUR est bien assigné")
# Test de tous les rôles
test_all_roles()

View File

@@ -11,22 +11,28 @@ class KeycloakRoleMapper {
/// Mapping des rôles Keycloak vers UserRole /// Mapping des rôles Keycloak vers UserRole
static const Map<String, UserRole> _keycloakToUserRole = { static const Map<String, UserRole> _keycloakToUserRole = {
// Rôles administratifs // Rôles administratifs
'SUPER_ADMINISTRATEUR': UserRole.superAdmin,
'ADMIN': UserRole.superAdmin, 'ADMIN': UserRole.superAdmin,
'ADMINISTRATEUR_ORGANISATION': UserRole.orgAdmin,
'PRESIDENT': UserRole.orgAdmin, 'PRESIDENT': UserRole.orgAdmin,
// Rôles de gestion // Rôles de gestion
'RESPONSABLE_TECHNIQUE': UserRole.moderator,
'RESPONSABLE_MEMBRES': UserRole.moderator,
'TRESORIER': UserRole.moderator, 'TRESORIER': UserRole.moderator,
'SECRETAIRE': UserRole.moderator, 'SECRETAIRE': UserRole.moderator,
'GESTIONNAIRE_MEMBRE': UserRole.moderator, 'GESTIONNAIRE_MEMBRE': UserRole.moderator,
'ORGANISATEUR_EVENEMENT': UserRole.moderator, 'ORGANISATEUR_EVENEMENT': UserRole.moderator,
// Rôles membres // Rôles membres
'MEMBRE_ACTIF': UserRole.activeMember,
'MEMBRE_SIMPLE': UserRole.simpleMember,
'MEMBRE': UserRole.activeMember, 'MEMBRE': UserRole.activeMember,
}; };
/// Mapping des rôles Keycloak vers permissions spécifiques /// Mapping des rôles Keycloak vers permissions spécifiques
static const Map<String, List<String>> _keycloakToPermissions = { static const Map<String, List<String>> _keycloakToPermissions = {
'ADMIN': [ 'SUPER_ADMINISTRATEUR': [
// Permissions Super Admin - Accès total // Permissions Super Admin - Accès total
PermissionMatrix.SYSTEM_ADMIN, PermissionMatrix.SYSTEM_ADMIN,
PermissionMatrix.SYSTEM_CONFIG, PermissionMatrix.SYSTEM_CONFIG,
@@ -46,6 +52,40 @@ class KeycloakRoleMapper {
PermissionMatrix.REPORTS_GENERATE, PermissionMatrix.REPORTS_GENERATE,
PermissionMatrix.DASHBOARD_ANALYTICS, PermissionMatrix.DASHBOARD_ANALYTICS,
], ],
'ADMIN': [
// Permissions Super Admin - Accès total (compatibilité)
PermissionMatrix.SYSTEM_ADMIN,
PermissionMatrix.SYSTEM_CONFIG,
PermissionMatrix.SYSTEM_SECURITY,
PermissionMatrix.ORG_CREATE,
PermissionMatrix.ORG_DELETE,
PermissionMatrix.ORG_CONFIG,
PermissionMatrix.MEMBERS_VIEW_ALL,
PermissionMatrix.MEMBERS_EDIT_ALL,
PermissionMatrix.MEMBERS_DELETE_ALL,
PermissionMatrix.FINANCES_VIEW_ALL,
PermissionMatrix.FINANCES_EDIT_ALL,
PermissionMatrix.EVENTS_VIEW_ALL,
PermissionMatrix.EVENTS_EDIT_ALL,
PermissionMatrix.SOLIDARITY_VIEW_ALL,
PermissionMatrix.SOLIDARITY_EDIT_ALL,
PermissionMatrix.REPORTS_GENERATE,
PermissionMatrix.DASHBOARD_ANALYTICS,
],
'ADMINISTRATEUR_ORGANISATION': [
// Permissions Admin Organisation
PermissionMatrix.ORG_CONFIG,
PermissionMatrix.MEMBERS_VIEW_ALL,
PermissionMatrix.MEMBERS_EDIT_ALL,
PermissionMatrix.FINANCES_VIEW_ALL,
PermissionMatrix.FINANCES_EDIT_ALL,
PermissionMatrix.EVENTS_VIEW_ALL,
PermissionMatrix.EVENTS_EDIT_ALL,
PermissionMatrix.SOLIDARITY_VIEW_ALL,
PermissionMatrix.SOLIDARITY_EDIT_ALL,
PermissionMatrix.REPORTS_GENERATE,
PermissionMatrix.DASHBOARD_ANALYTICS,
],
'PRESIDENT': [ 'PRESIDENT': [
// Permissions Président - Gestion organisation // Permissions Président - Gestion organisation
@@ -63,6 +103,31 @@ class KeycloakRoleMapper {
PermissionMatrix.COMM_SEND_ALL, PermissionMatrix.COMM_SEND_ALL,
], ],
'RESPONSABLE_TECHNIQUE': [
// Permissions Responsable Technique
PermissionMatrix.SYSTEM_MONITORING,
PermissionMatrix.SYSTEM_MAINTENANCE,
PermissionMatrix.MEMBERS_VIEW_ALL,
PermissionMatrix.MEMBERS_EDIT_BASIC,
PermissionMatrix.EVENTS_VIEW_ALL,
PermissionMatrix.EVENTS_EDIT_ALL,
PermissionMatrix.DASHBOARD_VIEW,
PermissionMatrix.REPORTS_GENERATE,
],
'RESPONSABLE_MEMBRES': [
// Permissions Responsable Membres
PermissionMatrix.MEMBERS_VIEW_ALL,
PermissionMatrix.MEMBERS_EDIT_ALL,
PermissionMatrix.MEMBERS_DELETE_ALL,
PermissionMatrix.EVENTS_VIEW_ALL,
PermissionMatrix.EVENTS_EDIT_ALL,
PermissionMatrix.SOLIDARITY_VIEW_ALL,
PermissionMatrix.SOLIDARITY_EDIT_ALL,
PermissionMatrix.DASHBOARD_VIEW,
PermissionMatrix.REPORTS_GENERATE,
],
'TRESORIER': [ 'TRESORIER': [
// Permissions Trésorier - Focus finances // Permissions Trésorier - Focus finances
PermissionMatrix.FINANCES_VIEW_ALL, PermissionMatrix.FINANCES_VIEW_ALL,
@@ -107,8 +172,35 @@ class KeycloakRoleMapper {
PermissionMatrix.COMM_SEND_MEMBERS, PermissionMatrix.COMM_SEND_MEMBERS,
], ],
'MEMBRE_ACTIF': [
// Permissions Membre Actif
PermissionMatrix.MEMBERS_VIEW_OWN,
PermissionMatrix.MEMBERS_EDIT_OWN,
PermissionMatrix.EVENTS_VIEW_ALL,
PermissionMatrix.EVENTS_PARTICIPATE,
PermissionMatrix.EVENTS_CREATE,
PermissionMatrix.SOLIDARITY_VIEW_ALL,
PermissionMatrix.SOLIDARITY_PARTICIPATE,
PermissionMatrix.SOLIDARITY_CREATE,
PermissionMatrix.FINANCES_VIEW_OWN,
PermissionMatrix.DASHBOARD_VIEW,
PermissionMatrix.COMM_SEND_MEMBERS,
],
'MEMBRE_SIMPLE': [
// Permissions Membre Simple
PermissionMatrix.MEMBERS_VIEW_OWN,
PermissionMatrix.MEMBERS_EDIT_OWN,
PermissionMatrix.EVENTS_VIEW_PUBLIC,
PermissionMatrix.EVENTS_PARTICIPATE,
PermissionMatrix.SOLIDARITY_VIEW_PUBLIC,
PermissionMatrix.SOLIDARITY_PARTICIPATE,
PermissionMatrix.FINANCES_VIEW_OWN,
PermissionMatrix.DASHBOARD_VIEW,
],
'MEMBRE': [ 'MEMBRE': [
// Permissions Membre Standard // Permissions Membre Standard (compatibilité)
PermissionMatrix.MEMBERS_VIEW_OWN, PermissionMatrix.MEMBERS_VIEW_OWN,
PermissionMatrix.MEMBERS_EDIT_OWN, PermissionMatrix.MEMBERS_EDIT_OWN,
PermissionMatrix.EVENTS_VIEW_PUBLIC, PermissionMatrix.EVENTS_VIEW_PUBLIC,
@@ -124,12 +216,18 @@ class KeycloakRoleMapper {
static UserRole mapToUserRole(List<String> keycloakRoles) { static UserRole mapToUserRole(List<String> keycloakRoles) {
// Priorité des rôles (du plus élevé au plus bas) // Priorité des rôles (du plus élevé au plus bas)
const List<String> rolePriority = [ const List<String> rolePriority = [
'SUPER_ADMINISTRATEUR',
'ADMIN', 'ADMIN',
'ADMINISTRATEUR_ORGANISATION',
'PRESIDENT', 'PRESIDENT',
'RESPONSABLE_TECHNIQUE',
'RESPONSABLE_MEMBRES',
'TRESORIER', 'TRESORIER',
'SECRETAIRE', 'SECRETAIRE',
'GESTIONNAIRE_MEMBRE', 'GESTIONNAIRE_MEMBRE',
'ORGANISATEUR_EVENEMENT', 'ORGANISATEUR_EVENEMENT',
'MEMBRE_ACTIF',
'MEMBRE_SIMPLE',
'MEMBRE', 'MEMBRE',
]; ];

View File

@@ -86,11 +86,15 @@ class DashboardActivityTile extends StatelessWidget {
fontSize: 12, fontSize: 12,
), ),
), ),
trailing: Text( trailing: SizedBox(
activity.time, width: 60,
style: TypographyTokens.labelSmall.copyWith( child: Text(
color: ColorTokens.onSurfaceVariant, activity.time,
fontSize: 11, style: TypographyTokens.labelSmall.copyWith(
color: ColorTokens.onSurfaceVariant,
fontSize: 11,
),
textAlign: TextAlign.end,
), ),
), ),
); );