Refactoring - Version OK
This commit is contained in:
@@ -44,11 +44,14 @@ public class AuthenticationFilter implements Filter {
|
|||||||
return;
|
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)) {
|
if (!hasRequiredPermissions(requestURI)) {
|
||||||
LOGGER.warning("Permissions insuffisantes pour: " + requestURI +
|
LOGGER.warning("Permissions insuffisantes pour: " + requestURI +
|
||||||
" (Utilisateur: " + userSession.getUsername() +
|
" (Utilisateur: " + (userSession != null ? userSession.getUsername() : "null") +
|
||||||
", Type: " + userSession.getTypeCompte() + ")");
|
", 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");
|
httpResponse.sendRedirect(httpRequest.getContextPath() + "/pages/secure/access-denied.xhtml");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -63,23 +66,43 @@ public class AuthenticationFilter implements Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasRequiredPermissions(String requestURI) {
|
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/")) {
|
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/")) {
|
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/")) {
|
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/")) {
|
if (requestURI.contains("/pages/secure/")) {
|
||||||
|
LOGGER.fine("Accès autorisé à la page sécurisée générale: " + requestURI);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGGER.warning("URI non reconnue dans hasRequiredPermissions: " + requestURI);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,10 @@ public class UserSession implements Serializable {
|
|||||||
|
|
||||||
// Récupérer les rôles depuis le token
|
// Récupérer les rôles depuis le token
|
||||||
this.roles = extractRolesFromToken();
|
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();
|
this.typeCompte = determineTypeCompte();
|
||||||
|
LOGGER.info("Type de compte déterminé: " + this.typeCompte);
|
||||||
|
|
||||||
// Mettre à jour les informations utilisateur
|
// Mettre à jour les informations utilisateur
|
||||||
this.currentUser = new CurrentUser();
|
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<String> extractRolesFromList(Object rolesObj) {
|
||||||
|
List<String> roles = new ArrayList<>();
|
||||||
|
if (rolesObj instanceof List) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Object> rolesList = (List<Object>) 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
|
* Extrait les rôles depuis le token JWT
|
||||||
*/
|
*/
|
||||||
@@ -96,26 +152,18 @@ public class UserSession implements Serializable {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
java.util.Map<String, Object> realmMap = (java.util.Map<String, Object>) realmAccess;
|
java.util.Map<String, Object> realmMap = (java.util.Map<String, Object>) realmAccess;
|
||||||
Object rolesObj = realmMap.get("roles");
|
Object rolesObj = realmMap.get("roles");
|
||||||
if (rolesObj instanceof List) {
|
List<String> realmRoles = extractRolesFromList(rolesObj);
|
||||||
@SuppressWarnings("unchecked")
|
if (!realmRoles.isEmpty()) {
|
||||||
List<String> realmRoles = (List<String>) rolesObj;
|
|
||||||
extractedRoles.addAll(realmRoles);
|
extractedRoles.addAll(realmRoles);
|
||||||
LOGGER.info("Rôles extraits depuis realm_access.roles: " + 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<String> realmRoles = (List<String>) realmAccess;
|
|
||||||
extractedRoles.addAll(realmRoles);
|
|
||||||
LOGGER.info("Rôles extraits depuis realm_access (liste directe): " + realmRoles);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (realmAccess instanceof List) {
|
} else if (realmAccess instanceof List) {
|
||||||
// Fallback: si realm_access est directement une liste de rôles
|
// Fallback: si realm_access est directement une liste de rôles
|
||||||
@SuppressWarnings("unchecked")
|
List<String> realmRoles = extractRolesFromList(realmAccess);
|
||||||
List<String> realmRoles = (List<String>) realmAccess;
|
if (!realmRoles.isEmpty()) {
|
||||||
extractedRoles.addAll(realmRoles);
|
extractedRoles.addAll(realmRoles);
|
||||||
LOGGER.info("Rôles extraits depuis realm_access (liste): " + realmRoles);
|
LOGGER.info("Rôles extraits depuis realm_access (liste): " + realmRoles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warning("Erreur lors de l'extraction des rôles realm: " + e.getMessage());
|
LOGGER.warning("Erreur lors de l'extraction des rôles realm: " + e.getMessage());
|
||||||
@@ -132,9 +180,8 @@ public class UserSession implements Serializable {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
java.util.Map<String, Object> clientMap = (java.util.Map<String, Object>) value;
|
java.util.Map<String, Object> clientMap = (java.util.Map<String, Object>) value;
|
||||||
Object rolesObj = clientMap.get("roles");
|
Object rolesObj = clientMap.get("roles");
|
||||||
if (rolesObj instanceof List) {
|
List<String> clientRoles = extractRolesFromList(rolesObj);
|
||||||
@SuppressWarnings("unchecked")
|
if (!clientRoles.isEmpty()) {
|
||||||
List<String> clientRoles = (List<String>) rolesObj;
|
|
||||||
extractedRoles.addAll(clientRoles);
|
extractedRoles.addAll(clientRoles);
|
||||||
LOGGER.info("Rôles extraits depuis resource_access: " + clientRoles);
|
LOGGER.info("Rôles extraits depuis resource_access: " + clientRoles);
|
||||||
}
|
}
|
||||||
@@ -149,9 +196,8 @@ public class UserSession implements Serializable {
|
|||||||
if (extractedRoles.isEmpty()) {
|
if (extractedRoles.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Object rolesClaim = jwt.getClaim("roles");
|
Object rolesClaim = jwt.getClaim("roles");
|
||||||
if (rolesClaim instanceof List) {
|
List<String> directRoles = extractRolesFromList(rolesClaim);
|
||||||
@SuppressWarnings("unchecked")
|
if (!directRoles.isEmpty()) {
|
||||||
List<String> directRoles = (List<String>) rolesClaim;
|
|
||||||
extractedRoles.addAll(directRoles);
|
extractedRoles.addAll(directRoles);
|
||||||
LOGGER.info("Rôles extraits depuis claim 'roles': " + 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
|
* Détermine le type de compte depuis les rôles
|
||||||
*/
|
*/
|
||||||
private String determineTypeCompte() {
|
private String determineTypeCompte() {
|
||||||
if (roles == null || roles.isEmpty()) {
|
// Utiliser this.roles pour s'assurer qu'on utilise la bonne variable d'instance
|
||||||
|
List<String> rolesToCheck = this.roles;
|
||||||
|
|
||||||
|
if (rolesToCheck == null || rolesToCheck.isEmpty()) {
|
||||||
|
LOGGER.warning("Aucun rôle trouvé, type de compte par défaut: MEMBRE");
|
||||||
return "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";
|
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";
|
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";
|
return "MEMBRE";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +361,11 @@ public class UserSession implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getTypeCompte() {
|
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;
|
return typeCompte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,17 +29,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<div class="flex gap-3 justify-content-center">
|
<h:form>
|
||||||
<p:commandButton value="Retour au tableau de bord"
|
<div class="flex gap-3 justify-content-center">
|
||||||
icon="pi pi-home"
|
<ui:include src="/templates/components/button-primary.xhtml">
|
||||||
styleClass="ui-button-outlined"
|
<ui:param name="value" value="Retour au tableau de bord" />
|
||||||
action="#{navigationBean.goToDashboard}" />
|
<ui:param name="icon" value="pi pi-home" />
|
||||||
|
<ui:param name="action" value="#{navigationBean.goToDashboard}" />
|
||||||
<p:commandButton value="Se déconnecter"
|
<ui:param name="outlined" value="true" />
|
||||||
icon="pi pi-sign-out"
|
</ui:include>
|
||||||
styleClass="ui-button-outlined ui-button-secondary"
|
|
||||||
action="#{loginBean.logout}" />
|
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||||
</div>
|
<ui:param name="value" value="Se déconnecter" />
|
||||||
|
<ui:param name="icon" value="pi pi-sign-out" />
|
||||||
|
<ui:param name="action" value="#{loginBean.logout}" />
|
||||||
|
<ui:param name="outlined" value="true" />
|
||||||
|
</ui:include>
|
||||||
|
</div>
|
||||||
|
</h:form>
|
||||||
|
|
||||||
<!-- Contact support -->
|
<!-- Contact support -->
|
||||||
<div class="mt-5 pt-4 border-top-1 surface-border">
|
<div class="mt-5 pt-4 border-top-1 surface-border">
|
||||||
|
|||||||
Reference in New Issue
Block a user