feat: sécuriser endpoints organisations + stats par org + fix IP dev
- PUT /{id}: check appartenance ADMIN_ORGANISATION (403 si pas membre)
- GET /statistiques: stats scoped à l'org active pour ADMIN_ORGANISATION
- OrganisationService.obtenirStatistiquesParOrganisation(): stats mono-org
- MembreOrganisationRepository.findByMembreEmailAndOrganisationId()
- application-dev: IP 192.168.1.145→localhost pour Keycloak
This commit is contained in:
@@ -17,9 +17,12 @@ import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
|
||||
import dev.lions.unionflow.server.security.OrganisationContextHolder;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
@@ -59,6 +62,8 @@ public class OrganisationResource {
|
||||
@Inject
|
||||
dev.lions.unionflow.server.repository.MembreOrganisationRepository membreOrganisationRepository;
|
||||
|
||||
@Inject OrganisationContextHolder organisationContextHolder;
|
||||
|
||||
/** Récupère les organisations du membre connecté (pour admin d'organisation) */
|
||||
@GET
|
||||
@Path("/mes")
|
||||
@@ -274,6 +279,27 @@ public class OrganisationResource {
|
||||
|
||||
LOG.infof("Mise à jour de l'organisation ID: %s", id);
|
||||
|
||||
// Ownership check: ADMIN_ORGANISATION can only update their own org
|
||||
Set<String> roles = securityIdentity.getRoles();
|
||||
boolean isOrgAdmin = roles.contains("ADMIN_ORGANISATION")
|
||||
&& !roles.contains("ADMIN")
|
||||
&& !roles.contains("SUPER_ADMIN");
|
||||
if (isOrgAdmin) {
|
||||
String email = securityIdentity.getPrincipal() != null
|
||||
? securityIdentity.getPrincipal().getName()
|
||||
: null;
|
||||
boolean belongsToOrg = email != null
|
||||
&& membreOrganisationRepository.findByMembreEmailAndOrganisationId(email, id)
|
||||
.filter(mo -> StatutMembre.ACTIF.equals(mo.getStatutMembre()))
|
||||
.isPresent();
|
||||
if (!belongsToOrg) {
|
||||
LOG.warnf("ADMIN_ORGANISATION %s attempted to update org %s without membership", email, id);
|
||||
return Response.status(Response.Status.FORBIDDEN)
|
||||
.entity(Map.of("error", "Vous n'êtes pas membre actif de cette organisation"))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Organisation organisationMiseAJour = organisationService.convertFromUpdateRequest(request);
|
||||
Organisation organisation =
|
||||
@@ -487,6 +513,19 @@ public class OrganisationResource {
|
||||
LOG.info("Récupération des statistiques des organisations");
|
||||
|
||||
try {
|
||||
// ADMIN_ORGANISATION (without ADMIN/SUPER_ADMIN) → scope to their active org
|
||||
Set<String> roles = securityIdentity.getRoles();
|
||||
boolean isOrgAdmin = roles.contains("ADMIN_ORGANISATION")
|
||||
&& !roles.contains("ADMIN")
|
||||
&& !roles.contains("SUPER_ADMIN");
|
||||
|
||||
if (isOrgAdmin && organisationContextHolder.hasContext()) {
|
||||
UUID orgId = organisationContextHolder.getOrganisationId();
|
||||
LOG.infof("ADMIN_ORGANISATION: scoping statistiques to org %s", orgId);
|
||||
Map<String, Object> statistiques = organisationService.obtenirStatistiquesParOrganisation(orgId);
|
||||
return Response.ok(statistiques).build();
|
||||
}
|
||||
|
||||
Map<String, Object> statistiques = organisationService.obtenirStatistiques();
|
||||
return Response.ok(statistiques).build();
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user