fix(security): audit RBAC complet v3.0 — rôles normalisés, lifecycle, changement mdp mobile

RBAC:
- HealthResource: @PermitAll
- RoleResource: @RolesAllowed ADMIN/SUPER_ADMIN/ADMIN_ORGANISATION class-level
- PropositionAideResource: @RolesAllowed MEMBRE/USER class-level
- AuthCallbackResource: @PermitAll
- EvenementResource: @PermitAll /publics et /test, count restreint
- BackupResource/LogsMonitoringResource/SystemResource: MODERATOR → MODERATEUR
- AnalyticsResource: MANAGER/MEMBER → ADMIN_ORGANISATION/MEMBRE
- RoleConstant.java: constantes de rôles centralisées

Cycle de vie membres:
- MemberLifecycleService: ajouterMembre()/retirerMembre() sur activation/radiation/archivage
- MembreResource: endpoint GET /numero/{numeroMembre}
- MembreService: méthode trouverParNumeroMembre()

Changement mot de passe:
- CompteAdherentResource: endpoint POST /auth/change-password (mobile)
- MembreKeycloakSyncService: changerMotDePasseDirectKeycloak() via API Admin Keycloak directe
- Fallback automatique si lions-user-manager indisponible

Workflow:
- Flyway V17-V23: rôles, types org, formules Option C, lifecycle columns, bareme cotisation
- Nouvelles classes: MemberLifecycleService, OrganisationModuleService, scheduler
- Security: OrganisationContextFilter, OrganisationContextHolder, ModuleAccessFilter
This commit is contained in:
dahoud
2026-04-07 20:52:26 +00:00
parent c74ae25ad6
commit a2dfae9a0b
78 changed files with 5637 additions and 271 deletions

View File

@@ -1,5 +1,6 @@
package dev.lions.unionflow.server.resource;
import dev.lions.unionflow.server.api.dto.common.ErrorResponse;
import dev.lions.unionflow.server.api.dto.notification.request.CreateNotificationRequest;
import dev.lions.unionflow.server.api.dto.notification.request.CreateTemplateNotificationRequest;
import dev.lions.unionflow.server.api.dto.notification.response.NotificationResponse;
@@ -61,7 +62,7 @@ public class NotificationResource {
} catch (Exception e) {
LOG.errorf(e, "Erreur liste notifications membre connecté");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur: " + e.getMessage()))
.build();
}
}
@@ -83,7 +84,7 @@ public class NotificationResource {
} catch (Exception e) {
LOG.errorf(e, "Erreur liste notifications non lues");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur: " + e.getMessage()))
.build();
}
}
@@ -107,12 +108,12 @@ public class NotificationResource {
return Response.status(Response.Status.CREATED).entity(result).build();
} catch (IllegalArgumentException e) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse(e.getMessage()))
.entity(ErrorResponse.ofError(e.getMessage()))
.build();
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de la création du template");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur lors de la création du template: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de la création du template: " + e.getMessage()))
.build();
}
}
@@ -136,7 +137,7 @@ public class NotificationResource {
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de la création de la notification");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur lors de la création de la notification: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de la création de la notification: " + e.getMessage()))
.build();
}
}
@@ -156,12 +157,12 @@ public class NotificationResource {
return Response.ok(result).build();
} catch (jakarta.ws.rs.NotFoundException e) {
return Response.status(Response.Status.NOT_FOUND)
.entity(new ErrorResponse("Notification non trouvée"))
.entity(ErrorResponse.ofError("Notification non trouvée"))
.build();
} catch (Exception e) {
LOG.errorf(e, "Erreur lors du marquage de la notification");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur lors du marquage de la notification: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors du marquage de la notification: " + e.getMessage()))
.build();
}
}
@@ -180,12 +181,12 @@ public class NotificationResource {
return Response.ok(result).build();
} catch (jakarta.ws.rs.NotFoundException e) {
return Response.status(Response.Status.NOT_FOUND)
.entity(new ErrorResponse("Notification non trouvée"))
.entity(ErrorResponse.ofError("Notification non trouvée"))
.build();
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de la recherche de la notification");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur lors de la recherche de la notification: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de la recherche de la notification: " + e.getMessage()))
.build();
}
}
@@ -205,7 +206,7 @@ public class NotificationResource {
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de la liste des notifications");
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse("Erreur lors de la liste des notifications: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de la liste des notifications: " + e.getMessage()))
.build();
}
}
@@ -225,9 +226,7 @@ public class NotificationResource {
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de la liste des notifications non lues");
return Response.status(Response.Status.BAD_REQUEST)
.entity(
new ErrorResponse(
"Erreur lors de la liste des notifications non lues: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de la liste des notifications non lues: " + e.getMessage()))
.build();
}
}
@@ -246,9 +245,7 @@ public class NotificationResource {
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de la liste des notifications en attente");
return Response.status(Response.Status.BAD_REQUEST)
.entity(
new ErrorResponse(
"Erreur lors de la liste des notifications en attente: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de la liste des notifications en attente: " + e.getMessage()))
.build();
}
}
@@ -269,27 +266,16 @@ public class NotificationResource {
return Response.ok(Map.of("notificationsCreees", notificationsCreees)).build();
} catch (IllegalArgumentException e) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(new ErrorResponse(e.getMessage()))
.entity(ErrorResponse.ofError(e.getMessage()))
.build();
} catch (Exception e) {
LOG.errorf(e, "Erreur lors de l'envoi des notifications groupées");
return Response.status(Response.Status.BAD_REQUEST)
.entity(
new ErrorResponse(
"Erreur lors de l'envoi des notifications groupées: " + e.getMessage()))
.entity(ErrorResponse.ofError("Erreur lors de l'envoi des notifications groupées: " + e.getMessage()))
.build();
}
}
/** Classe interne pour les réponses d'erreur */
public static class ErrorResponse {
public String error;
public ErrorResponse(String error) {
this.error = error;
}
}
/** Classe interne pour les requêtes de notifications groupées (WOU/DRY) */
public static class NotificationGroupeeRequest {
public List<UUID> membreIds;