From 087cd3694bd615cc66a6eb7b2373c6392bb977b1 Mon Sep 17 00:00:00 2001 From: dahoud Date: Mon, 17 Nov 2025 17:53:04 +0000 Subject: [PATCH] Refactoring - Version OK --- .../client/security/AuthenticationFilter.java | 37 +++- .../unionflow/client/view/UserSession.java | 160 +++++++++++++++--- .../pages/secure/access-denied.xhtml | 28 +-- 3 files changed, 183 insertions(+), 42 deletions(-) diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/security/AuthenticationFilter.java b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/security/AuthenticationFilter.java index 0ba5602..45558bc 100644 --- a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/security/AuthenticationFilter.java +++ b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/security/AuthenticationFilter.java @@ -44,11 +44,14 @@ public class AuthenticationFilter implements Filter { return; } - // Vérifier les autorisations spécifiques + // Vérifier les autorisations spécifiques basées sur les rôles + // Note: /pages/secure/access-denied.xhtml est autorisé car elle fait partie de /pages/secure/ + // qui est accessible à tous les utilisateurs authentifiés if (!hasRequiredPermissions(requestURI)) { LOGGER.warning("Permissions insuffisantes pour: " + requestURI + - " (Utilisateur: " + userSession.getUsername() + - ", Type: " + userSession.getTypeCompte() + ")"); + " (Utilisateur: " + (userSession != null ? userSession.getUsername() : "null") + + ", Type: " + (userSession != null ? userSession.getTypeCompte() : "null") + + ", Rôles: " + (userSession != null && userSession.getRoles() != null ? userSession.getRoles() : "null") + ")"); httpResponse.sendRedirect(httpRequest.getContextPath() + "/pages/secure/access-denied.xhtml"); return; } @@ -63,23 +66,43 @@ public class AuthenticationFilter implements Filter { } private boolean hasRequiredPermissions(String requestURI) { + // Vérifier que userSession est disponible + if (userSession == null) { + LOGGER.warning("UserSession est null lors de la vérification des permissions pour: " + requestURI); + return false; + } + + // Pages super-admin : nécessitent le rôle SUPER_ADMIN if (requestURI.contains("/pages/super-admin/")) { - return userSession.isSuperAdmin(); + boolean isSuperAdmin = userSession.isSuperAdmin(); + LOGGER.fine("Vérification SUPER_ADMIN pour " + requestURI + ": " + isSuperAdmin + + " (Type: " + userSession.getTypeCompte() + ", Rôles: " + userSession.getRoles() + ")"); + return isSuperAdmin; } + // Pages admin : nécessitent ADMIN_ENTITE ou SUPER_ADMIN if (requestURI.contains("/pages/admin/")) { - return userSession.isAdmin(); + boolean isAdmin = userSession.isAdmin(); + LOGGER.fine("Vérification ADMIN pour " + requestURI + ": " + isAdmin + + " (Type: " + userSession.getTypeCompte() + ", Rôles: " + userSession.getRoles() + ")"); + return isAdmin; } + // Pages membre : nécessitent le rôle MEMBRE ou tout utilisateur authentifié if (requestURI.contains("/pages/membre/")) { - return userSession.isMembre(); + boolean isMembre = userSession.isMembre(); + LOGGER.fine("Vérification MEMBRE pour " + requestURI + ": " + isMembre + + " (Type: " + userSession.getTypeCompte() + ", Rôles: " + userSession.getRoles() + ")"); + return isMembre; } - // Pages sécurisées générales - tout utilisateur authentifié + // Pages sécurisées générales - tout utilisateur authentifié peut y accéder if (requestURI.contains("/pages/secure/")) { + LOGGER.fine("Accès autorisé à la page sécurisée générale: " + requestURI); return true; } + LOGGER.warning("URI non reconnue dans hasRequiredPermissions: " + requestURI); return false; } diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/UserSession.java b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/UserSession.java index 9c09e67..f91eba9 100644 --- a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/UserSession.java +++ b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/UserSession.java @@ -58,7 +58,10 @@ public class UserSession implements Serializable { // Récupérer les rôles depuis le token this.roles = extractRolesFromToken(); + LOGGER.info("Rôles assignés à this.roles: " + this.roles); + LOGGER.info("Vérification contains('SUPER_ADMIN'): " + (this.roles != null && this.roles.contains("SUPER_ADMIN"))); this.typeCompte = determineTypeCompte(); + LOGGER.info("Type de compte déterminé: " + this.typeCompte); // Mettre à jour les informations utilisateur this.currentUser = new CurrentUser(); @@ -83,6 +86,59 @@ public class UserSession implements Serializable { } } + /** + * Convertit un objet JSON en String de manière sécurisée + * Gère les cas où l'objet est un JsonStringImpl, String, ou autre type + */ + private String convertToString(Object obj) { + if (obj == null) { + return null; + } + if (obj instanceof String) { + String str = (String) obj; + // Nettoyer les guillemets qui pourraient être présents + str = str.trim(); + if (str.startsWith("'") && str.endsWith("'") && str.length() > 1) { + str = str.substring(1, str.length() - 1); + } + if (str.startsWith("\"") && str.endsWith("\"") && str.length() > 1) { + str = str.substring(1, str.length() - 1); + } + return str.trim(); + } + // Gérer JsonStringImpl et autres types JSON + String str = obj.toString(); + // Nettoyer les guillemets qui pourraient être présents + str = str.trim(); + if (str.startsWith("'") && str.endsWith("'") && str.length() > 1) { + str = str.substring(1, str.length() - 1); + } + if (str.startsWith("\"") && str.endsWith("\"") && str.length() > 1) { + str = str.substring(1, str.length() - 1); + } + return str.trim(); + } + + /** + * Extrait et convertit une liste de rôles depuis un objet JSON + */ + private List extractRolesFromList(Object rolesObj) { + List roles = new ArrayList<>(); + if (rolesObj instanceof List) { + @SuppressWarnings("unchecked") + List rolesList = (List) rolesObj; + for (Object roleObj : rolesList) { + String role = convertToString(roleObj); + if (role != null && !role.isEmpty()) { + // S'assurer que c'est vraiment un String en créant une nouvelle instance + roles.add(new String(role)); + LOGGER.fine("Rôle converti: '" + role + "' (type: " + role.getClass().getName() + ")"); + } + } + } + return roles; + } + /** * Extrait les rôles depuis le token JWT */ @@ -96,26 +152,18 @@ public class UserSession implements Serializable { @SuppressWarnings("unchecked") java.util.Map realmMap = (java.util.Map) realmAccess; Object rolesObj = realmMap.get("roles"); - if (rolesObj instanceof List) { - @SuppressWarnings("unchecked") - List realmRoles = (List) rolesObj; + List realmRoles = extractRolesFromList(rolesObj); + if (!realmRoles.isEmpty()) { extractedRoles.addAll(realmRoles); LOGGER.info("Rôles extraits depuis realm_access.roles: " + realmRoles); - } else { - // Fallback: si realm_access est directement une liste de rôles - if (realmAccess instanceof List) { - @SuppressWarnings("unchecked") - List realmRoles = (List) realmAccess; - extractedRoles.addAll(realmRoles); - LOGGER.info("Rôles extraits depuis realm_access (liste directe): " + realmRoles); - } } } else if (realmAccess instanceof List) { // Fallback: si realm_access est directement une liste de rôles - @SuppressWarnings("unchecked") - List realmRoles = (List) realmAccess; - extractedRoles.addAll(realmRoles); - LOGGER.info("Rôles extraits depuis realm_access (liste): " + realmRoles); + List realmRoles = extractRolesFromList(realmAccess); + if (!realmRoles.isEmpty()) { + extractedRoles.addAll(realmRoles); + LOGGER.info("Rôles extraits depuis realm_access (liste): " + realmRoles); + } } } catch (Exception e) { LOGGER.warning("Erreur lors de l'extraction des rôles realm: " + e.getMessage()); @@ -132,9 +180,8 @@ public class UserSession implements Serializable { @SuppressWarnings("unchecked") java.util.Map clientMap = (java.util.Map) value; Object rolesObj = clientMap.get("roles"); - if (rolesObj instanceof List) { - @SuppressWarnings("unchecked") - List clientRoles = (List) rolesObj; + List clientRoles = extractRolesFromList(rolesObj); + if (!clientRoles.isEmpty()) { extractedRoles.addAll(clientRoles); LOGGER.info("Rôles extraits depuis resource_access: " + clientRoles); } @@ -149,9 +196,8 @@ public class UserSession implements Serializable { if (extractedRoles.isEmpty()) { try { Object rolesClaim = jwt.getClaim("roles"); - if (rolesClaim instanceof List) { - @SuppressWarnings("unchecked") - List directRoles = (List) rolesClaim; + List directRoles = extractRolesFromList(rolesClaim); + if (!directRoles.isEmpty()) { extractedRoles.addAll(directRoles); LOGGER.info("Rôles extraits depuis claim 'roles': " + directRoles); } @@ -168,17 +214,78 @@ public class UserSession implements Serializable { * Détermine le type de compte depuis les rôles */ private String determineTypeCompte() { - if (roles == null || roles.isEmpty()) { + // Utiliser this.roles pour s'assurer qu'on utilise la bonne variable d'instance + List rolesToCheck = this.roles; + + if (rolesToCheck == null || rolesToCheck.isEmpty()) { + LOGGER.warning("Aucun rôle trouvé, type de compte par défaut: MEMBRE"); return "MEMBRE"; } - if (roles.contains("SUPER_ADMIN") || roles.contains("super-admin")) { + LOGGER.info("Détermination du type de compte depuis les rôles: " + rolesToCheck); + LOGGER.info("Nombre de rôles: " + rolesToCheck.size()); + + // Vérifier le type des éléments de la liste + if (!rolesToCheck.isEmpty()) { + Object firstRole = rolesToCheck.get(0); + LOGGER.info("Type du premier rôle: " + (firstRole != null ? firstRole.getClass().getName() : "null")); + LOGGER.info("Premier rôle (toString): '" + firstRole + "'"); + LOGGER.info("Premier rôle (length): " + (firstRole != null ? firstRole.toString().length() : 0)); + // Vérifier les caractères du premier rôle + if (firstRole != null) { + String firstRoleStr = firstRole.toString(); + LOGGER.info("Premier rôle (bytes): " + java.util.Arrays.toString(firstRoleStr.getBytes())); + } + } + + // Vérifier SUPER_ADMIN en parcourant la liste (plus robuste que contains) + for (String role : rolesToCheck) { + if (role != null) { + // Nettoyer la chaîne : retirer les guillemets et espaces + String roleStr = role.toString().trim(); + // Retirer les guillemets simples et doubles au début et à la fin + if (roleStr.startsWith("'") && roleStr.endsWith("'")) { + roleStr = roleStr.substring(1, roleStr.length() - 1); + } + if (roleStr.startsWith("\"") && roleStr.endsWith("\"")) { + roleStr = roleStr.substring(1, roleStr.length() - 1); + } + roleStr = roleStr.trim(); + + LOGGER.info("Vérification du rôle: '" + roleStr + "' (longueur: " + roleStr.length() + ", original: '" + role + "')"); + if ("SUPER_ADMIN".equals(roleStr) || "super-admin".equalsIgnoreCase(roleStr)) { + LOGGER.info("✅ Type de compte détecté: SUPER_ADMIN (rôle trouvé: '" + roleStr + "')"); + return "SUPER_ADMIN"; + } + } + } + + // Fallback: utiliser contains() pour compatibilité + boolean hasSuperAdmin = rolesToCheck.contains("SUPER_ADMIN"); + boolean hasSuperAdminLower = rolesToCheck.contains("super-admin"); + LOGGER.info("Contient 'SUPER_ADMIN' (contains): " + hasSuperAdmin); + LOGGER.info("Contient 'super-admin' (contains): " + hasSuperAdminLower); + + if (hasSuperAdmin || hasSuperAdminLower) { + LOGGER.info("✅ Type de compte détecté: SUPER_ADMIN (via contains)"); return "SUPER_ADMIN"; } - if (roles.contains("ADMIN") || roles.contains("admin") || roles.contains("ADMIN_ENTITE")) { + + // Vérifier ADMIN_ENTITE (mais pas si c'est juste "ADMIN" qui pourrait être ambigu) + if (rolesToCheck.contains("ADMIN_ENTITE")) { + LOGGER.info("Type de compte détecté: ADMIN_ENTITE"); return "ADMIN_ENTITE"; } + // Vérifier les autres rôles admin (avec précaution pour éviter les faux positifs) + for (String role : rolesToCheck) { + if (role != null && (role.equals("ADMIN") || role.equalsIgnoreCase("admin"))) { + LOGGER.info("Type de compte détecté: ADMIN_ENTITE (via rôle ADMIN)"); + return "ADMIN_ENTITE"; + } + } + + LOGGER.warning("Aucun rôle admin trouvé, type de compte par défaut: MEMBRE"); return "MEMBRE"; } @@ -254,6 +361,11 @@ public class UserSession implements Serializable { } public String getTypeCompte() { + // Si le type de compte n'est pas encore déterminé, l'initialiser + if (typeCompte == null && jwt != null && jwt.getName() != null) { + LOGGER.info("getTypeCompte() appelé avant initialisation, initialisation en cours..."); + initializeFromOidcToken(); + } return typeCompte; } diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/access-denied.xhtml b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/access-denied.xhtml index 1aa1548..8b21c76 100644 --- a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/access-denied.xhtml +++ b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/access-denied.xhtml @@ -29,17 +29,23 @@ -
- - - -
+ +
+ + + + + + + + + + + + + +
+