commit 04b4aa47f842c469e0a5a150fe0a9f07df47d2fa Author: dahoud Date: Sun Nov 9 17:06:04 2025 +0000 feat: Module server-api initial Module d'API pour lions-user-manager Contenu: - DTOs (User, Role, Audit, Search) - Enums (StatutUser, TypeRole, TypeActionAudit) - Service interfaces (UserService, RoleService, AuditService, SyncService) - ValidationConstants Statut: ✅ 100% complété 🤖 Generated with Claude Code Co-Authored-By: Claude diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..73aa689 --- /dev/null +++ b/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + + dev.lions.user.manager + lions-user-manager-parent + 1.0.0 + + + lions-user-manager-server-api + jar + + Lions User Manager - Server API + Contrats API: DTOs, interfaces de services, enums et validations + + + + + org.projectlombok + lombok + + + + + jakarta.validation + jakarta.validation-api + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + + + com.fasterxml.jackson.core + jackson-annotations + + + + + org.eclipse.microprofile.openapi + microprofile-openapi-api + + + + + org.junit.jupiter + junit-jupiter + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + diff --git a/src/main/java/dev/lions/user/manager/dto/audit/AuditLogDTO.java b/src/main/java/dev/lions/user/manager/dto/audit/AuditLogDTO.java new file mode 100644 index 0000000..5c42f39 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/audit/AuditLogDTO.java @@ -0,0 +1,178 @@ +package dev.lions.user.manager.dto.audit; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import dev.lions.user.manager.dto.base.BaseDTO; +import dev.lions.user.manager.enums.audit.TypeActionAudit; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * DTO représentant une entrée d'audit + * Enregistre toutes les actions effectuées via l'API de gestion + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Entrée d'audit des actions utilisateur") +public class AuditLogDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + // Qui a fait l'action + @Schema(description = "ID de l'utilisateur qui a effectué l'action", example = "f47ac10b-58cc-4372-a567-0e02b2c3d479") + private String acteurUserId; + + @Schema(description = "Username de l'utilisateur qui a effectué l'action", example = "admin@lions.dev") + private String acteurUsername; + + @Schema(description = "Nom complet de l'acteur", example = "Admin Principal") + private String acteurNomComplet; + + @Schema(description = "Rôles de l'acteur au moment de l'action") + private String acteurRoles; + + // Quand + @Schema(description = "Date et heure de l'action", example = "2025-01-15T10:30:00") + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime dateAction; + + // Quoi + @Schema(description = "Type d'action effectuée", example = "USER_CREATE") + private TypeActionAudit typeAction; + + @Schema(description = "Type de ressource affectée", example = "USER") + private String ressourceType; + + @Schema(description = "ID de la ressource affectée", example = "a1b2c3d4-e5f6-7890-1234-567890abcdef") + private String ressourceId; + + @Schema(description = "Nom/Identifiant de la ressource", example = "jdupont") + private String ressourceName; + + // Où + @Schema(description = "Nom du Realm", example = "btpxpress") + private String realmName; + + @Schema(description = "Adresse IP de l'acteur", example = "192.168.1.100") + private String ipAddress; + + @Schema(description = "User-Agent du client", example = "Mozilla/5.0...") + private String userAgent; + + @Schema(description = "Localisation géographique", example = "Abidjan, Côte d'Ivoire") + private String geolocation; + + // Comment + @Schema(description = "Endpoint API appelé", example = "/api/users/create") + private String apiEndpoint; + + @Schema(description = "Méthode HTTP", example = "POST") + private String httpMethod; + + // Détails + @Schema(description = "Description de l'action", example = "Création d'un nouvel utilisateur") + private String description; + + @Schema(description = "Détails de l'action au format JSON") + private String detailsJson; + + @Schema(description = "Ancienne valeur (avant modification)") + private String oldValue; + + @Schema(description = "Nouvelle valeur (après modification)") + private String newValue; + + @Schema(description = "Différences entre ancienne et nouvelle valeur") + private String diff; + + // Résultat + @Schema(description = "Succès de l'opération", example = "true") + private Boolean success; + + @Schema(description = "Code d'erreur (si échec)", example = "USER_ALREADY_EXISTS") + private String errorCode; + + @Schema(description = "Message d'erreur (si échec)") + private String errorMessage; + + @Schema(description = "Trace d'erreur complète (si échec)") + private String stackTrace; + + // Métadonnées + @Schema(description = "Durée d'exécution en millisecondes", example = "145") + private Long executionTimeMs; + + @Schema(description = "ID de session/transaction", example = "sess_abc123") + private String sessionId; + + @Schema(description = "ID de corrélation (pour tracer requêtes liées)", example = "corr_xyz789") + private String correlationId; + + @Schema(description = "Raison de l'action", example = "Demande du manager") + private String raison; + + @Schema(description = "Commentaires administratifs", example = "Promotion suite à évaluation annuelle") + private String commentaires; + + @Schema(description = "Métadonnées supplémentaires") + private Map metadata; + + // Flags + @Schema(description = "Indique si l'action est critique", example = "false") + private Boolean critique; + + @Schema(description = "Indique si l'action nécessite une alerte", example = "false") + private Boolean requiresAlert; + + @Schema(description = "Indique si l'action a été notifiée", example = "true") + private Boolean notified; + + /** + * Détermine si l'action a réussi + * @return true si success = true + */ + public boolean isSuccessful() { + return Boolean.TRUE.equals(success); + } + + /** + * Détermine si l'action a échoué + * @return true si success = false + */ + public boolean isFailed() { + return Boolean.FALSE.equals(success); + } + + /** + * Détermine si l'action est critique + * @return true si critique = true ou si typeAction est critique + */ + public boolean isCritique() { + return Boolean.TRUE.equals(critique) || (typeAction != null && typeAction.isCritical()); + } + + /** + * Retourne un résumé court de l'action + * @return résumé + */ + public String getSummary() { + return String.format("%s: %s effectué par %s sur %s %s", + dateAction, + typeAction != null ? typeAction.getLibelle() : "Action inconnue", + acteurUsername != null ? acteurUsername : "Inconnu", + ressourceType != null ? ressourceType : "Ressource", + ressourceName != null ? ressourceName : ressourceId + ); + } +} diff --git a/src/main/java/dev/lions/user/manager/dto/base/BaseDTO.java b/src/main/java/dev/lions/user/manager/dto/base/BaseDTO.java new file mode 100644 index 0000000..cbfae0b --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/base/BaseDTO.java @@ -0,0 +1,47 @@ +package dev.lions.user.manager.dto.base; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * DTO de base pour tous les objets métier + * Contient les attributs communs (id, dates, audit) + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "DTO de base contenant les attributs communs à tous les objets") +public abstract class BaseDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "Identifiant unique (UUID Keycloak)", example = "f47ac10b-58cc-4372-a567-0e02b2c3d479") + private String id; + + @Schema(description = "Date de création", example = "2025-01-15T10:30:00") + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime dateCreation; + + @Schema(description = "Date de dernière modification", example = "2025-01-15T14:20:00") + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime dateModification; + + @Schema(description = "Utilisateur ayant créé l'entité", example = "admin@lions.dev") + private String creeParUsername; + + @Schema(description = "Utilisateur ayant modifié l'entité", example = "superadmin@lions.dev") + private String modifieParUsername; + + @Schema(description = "Numéro de version pour gestion optimiste", example = "1") + private Long version; +} diff --git a/src/main/java/dev/lions/user/manager/dto/role/RoleAssignmentDTO.java b/src/main/java/dev/lions/user/manager/dto/role/RoleAssignmentDTO.java new file mode 100644 index 0000000..f2da065 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/role/RoleAssignmentDTO.java @@ -0,0 +1,101 @@ +package dev.lions.user.manager.dto.role; + +import com.fasterxml.jackson.annotation.JsonInclude; +import dev.lions.user.manager.enums.role.TypeRole; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.io.Serializable; +import java.util.List; + +/** + * DTO pour assigner ou révoquer des rôles à un utilisateur + * Utilisé dans les opérations d'attribution de rôles + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Attribution ou révocation de rôles") +public class RoleAssignmentDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotBlank(message = "L'ID utilisateur est obligatoire") + @Schema(description = "ID de l'utilisateur cible", example = "f47ac10b-58cc-4372-a567-0e02b2c3d479", required = true) + private String userId; + + @Schema(description = "Username de l'utilisateur cible (optionnel)", example = "jdupont") + private String username; + + @NotEmpty(message = "Au moins un rôle doit être spécifié") + @Schema(description = "Liste des noms de rôles à attribuer ou révoquer", required = true) + private List roleNames; + + @Schema(description = "Liste des IDs de rôles à attribuer ou révoquer") + private List roleIds; + + @NotNull(message = "Le type de rôle est obligatoire") + @Schema(description = "Type de rôle", example = "REALM_ROLE", required = true) + private TypeRole typeRole; + + @Schema(description = "Nom du Realm", example = "btpxpress") + private String realmName; + + @Schema(description = "Nom du Client (requis si typeRole = CLIENT_ROLE)", example = "btpxpress-app") + private String clientName; + + @Schema(description = "ID du Client (optionnel)") + private String clientId; + + @Schema(description = "Raison de l'attribution/révocation", example = "Promotion au poste de gestionnaire") + private String raison; + + @Schema(description = "Commentaires administratifs", example = "Demandé par le manager") + private String commentaires; + + @Schema(description = "Indique si c'est une attribution temporaire", example = "false") + private Boolean temporaire; + + @Schema(description = "Date d'expiration de l'attribution temporaire", example = "2025-12-31T23:59:59") + private String dateExpiration; + + @Schema(description = "Indique si les rôles composites doivent être inclus", example = "true") + @Builder.Default + private Boolean includeComposites = true; + + @Schema(description = "Indique si l'opération doit notifier l'utilisateur", example = "true") + @Builder.Default + private Boolean notifyUser = false; + + /** + * Valide que les données nécessaires sont présentes pour un rôle client + * @return true si valide + */ + public boolean isValidForClientRole() { + return typeRole == TypeRole.CLIENT_ROLE && clientName != null && !clientName.isBlank(); + } + + /** + * Valide que les données nécessaires sont présentes pour un rôle realm + * @return true si valide + */ + public boolean isValidForRealmRole() { + return typeRole == TypeRole.REALM_ROLE; + } + + /** + * Retourne le nombre de rôles à assigner/révoquer + * @return nombre de rôles + */ + public int getRoleCount() { + return roleNames != null ? roleNames.size() : 0; + } +} diff --git a/src/main/java/dev/lions/user/manager/dto/role/RoleDTO.java b/src/main/java/dev/lions/user/manager/dto/role/RoleDTO.java new file mode 100644 index 0000000..90e1958 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/role/RoleDTO.java @@ -0,0 +1,144 @@ +package dev.lions.user.manager.dto.role; + +import com.fasterxml.jackson.annotation.JsonInclude; +import dev.lions.user.manager.dto.base.BaseDTO; +import dev.lions.user.manager.enums.role.TypeRole; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.util.List; +import java.util.Map; + +/** + * DTO représentant un rôle Keycloak + * Mappé depuis RoleRepresentation de Keycloak Admin API + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Rôle Keycloak (Realm ou Client)") +public class RoleDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @NotBlank(message = "Le nom du rôle est obligatoire") + @Size(min = 2, max = 100, message = "Le nom du rôle doit contenir entre 2 et 100 caractères") + @Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "Le nom du rôle ne peut contenir que des lettres, chiffres, underscores et tirets") + @Schema(description = "Nom du rôle", example = "admin_btpxpress", required = true) + private String name; + + @Schema(description = "Description du rôle", example = "Administrateur avec tous les privilèges") + private String description; + + @Schema(description = "Type de rôle", example = "REALM_ROLE") + private TypeRole typeRole; + + @Schema(description = "Indique si c'est un rôle composite", example = "false") + private Boolean composite; + + @Schema(description = "ID du conteneur (Realm ou Client)", example = "btpxpress") + private String containerId; + + @Schema(description = "Nom du Realm", example = "btpxpress") + private String realmName; + + @Schema(description = "Nom du Client (si rôle client)", example = "btpxpress-app") + private String clientName; + + @Schema(description = "ID du Client (si rôle client)") + private String clientId; + + @Schema(description = "Rôles composites inclus dans ce rôle") + private List compositeRoles; + + @Schema(description = "Rôles Realm composites") + private List compositeRealmRoles; + + @Schema(description = "Rôles Client composites par client") + private Map> compositeClientRoles; + + @Schema(description = "Attributs personnalisés du rôle") + private Map> attributes; + + @Schema(description = "Nombre d'utilisateurs ayant ce rôle", example = "15") + private Integer userCount; + + @Schema(description = "Indique si le rôle est un rôle système", example = "false") + private Boolean systemRole; + + @Schema(description = "Indique si le rôle peut être supprimé", example = "true") + private Boolean deletable; + + /** + * Détermine si c'est un rôle Realm + * @return true si typeRole est REALM_ROLE + */ + public boolean isRealmRole() { + return typeRole == TypeRole.REALM_ROLE; + } + + /** + * Détermine si c'est un rôle Client + * @return true si typeRole est CLIENT_ROLE + */ + public boolean isClientRole() { + return typeRole == TypeRole.CLIENT_ROLE; + } + + /** + * Détermine si le rôle est composite + * @return true si composite = true et a des rôles composites + */ + public boolean isComposite() { + return Boolean.TRUE.equals(composite) + && ((compositeRoles != null && !compositeRoles.isEmpty()) + || (compositeRealmRoles != null && !compositeRealmRoles.isEmpty()) + || (compositeClientRoles != null && !compositeClientRoles.isEmpty())); + } + + /** + * Retourne le nom complet du rôle (avec préfixe client si applicable) + * @return nom complet + */ + public String getFullName() { + if (isClientRole() && clientName != null) { + return clientName + ":" + name; + } + return name; + } + + /** + * DTO pour rôle composite + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @SuperBuilder + @Schema(description = "Rôle composite") + public static class RoleCompositeDTO { + @Schema(description = "ID du rôle", example = "f47ac10b-58cc-4372-a567-0e02b2c3d479") + private String id; + + @Schema(description = "Nom du rôle", example = "gestionnaire") + private String name; + + @Schema(description = "Description du rôle") + private String description; + + @Schema(description = "Type de rôle", example = "REALM_ROLE") + private TypeRole typeRole; + + @Schema(description = "Nom du client (si client role)") + private String clientName; + } +} diff --git a/src/main/java/dev/lions/user/manager/dto/user/UserDTO.java b/src/main/java/dev/lions/user/manager/dto/user/UserDTO.java new file mode 100644 index 0000000..544fc34 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/user/UserDTO.java @@ -0,0 +1,209 @@ +package dev.lions.user.manager.dto.user; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import dev.lions.user.manager.dto.base.BaseDTO; +import dev.lions.user.manager.enums.user.StatutUser; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * DTO représentant un utilisateur Keycloak + * Mappé depuis la représentation UserRepresentation de Keycloak Admin API + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Utilisateur Keycloak") +public class UserDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + // Informations de base + @NotBlank(message = "Le nom d'utilisateur est obligatoire") + @Size(min = 3, max = 100, message = "Le nom d'utilisateur doit contenir entre 3 et 100 caractères") + @Pattern(regexp = "^[a-zA-Z0-9._-]+$", message = "Le nom d'utilisateur ne peut contenir que des lettres, chiffres, points, tirets et underscores") + @Schema(description = "Nom d'utilisateur unique", example = "jdupont", required = true) + private String username; + + @NotBlank(message = "L'email est obligatoire") + @Email(message = "Format d'email invalide") + @Schema(description = "Adresse email", example = "jean.dupont@lions.dev", required = true) + private String email; + + @Schema(description = "Email vérifié", example = "true") + private Boolean emailVerified; + + @NotBlank(message = "Le prénom est obligatoire") + @Size(min = 2, max = 100, message = "Le prénom doit contenir entre 2 et 100 caractères") + @Schema(description = "Prénom", example = "Jean", required = true) + private String prenom; + + @NotBlank(message = "Le nom est obligatoire") + @Size(min = 2, max = 100, message = "Le nom doit contenir entre 2 et 100 caractères") + @Schema(description = "Nom de famille", example = "Dupont", required = true) + private String nom; + + // Statut + @Schema(description = "Statut de l'utilisateur", example = "ACTIF") + private StatutUser statut; + + @Schema(description = "Compte activé", example = "true") + private Boolean enabled; + + // Informations supplémentaires + @Schema(description = "Numéro de téléphone", example = "+225 07 12 34 56 78") + private String telephone; + + @Schema(description = "Organisation/Entreprise", example = "Lions Dev") + private String organisation; + + @Schema(description = "Département", example = "IT") + private String departement; + + @Schema(description = "Fonction/Poste", example = "Développeur Senior") + private String fonction; + + @Schema(description = "Pays", example = "Côte d'Ivoire") + private String pays; + + @Schema(description = "Ville", example = "Abidjan") + private String ville; + + @Schema(description = "Langue préférée", example = "fr") + private String langue; + + @Schema(description = "Fuseau horaire", example = "Africa/Abidjan") + private String timezone; + + // Realm et rôles + @Schema(description = "Realm Keycloak", example = "btpxpress") + private String realmName; + + @Schema(description = "Liste des rôles Realm assignés") + private List realmRoles; + + @Schema(description = "Liste des rôles Client assignés") + private Map> clientRoles; + + @Schema(description = "Liste des groupes auxquels appartient l'utilisateur") + private List groups; + + // Dates importantes + @Schema(description = "Date de dernière connexion", example = "2025-01-15T10:30:00") + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime derniereConnexion; + + @Schema(description = "Date d'expiration du compte", example = "2026-01-15T23:59:59") + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime dateExpiration; + + @Schema(description = "Date de verrouillage du compte", example = "2025-01-15T16:00:00") + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime dateVerrouillage; + + // Attributs personnalisés Keycloak + @Schema(description = "Attributs personnalisés Keycloak") + private Map> attributes; + + // Actions requises + @Schema(description = "Actions requises (ex: UPDATE_PASSWORD, VERIFY_EMAIL)") + private List requiredActions; + + // Fédération + @Schema(description = "Fournisseur d'identité fédéré", example = "google") + private String federatedIdentityProvider; + + @Schema(description = "Lien d'identité fédérée") + private List federatedIdentities; + + // Crédentiels temporaires + @Schema(description = "Mot de passe temporaire (création uniquement)") + private String temporaryPassword; + + @Schema(description = "Indique si le mot de passe est temporaire") + private Boolean temporaryPasswordFlag; + + // Informations de session + @Schema(description = "Nombre de sessions actives", example = "2") + private Integer activeSessions; + + @Schema(description = "Nombre d'échecs de connexion", example = "0") + private Integer failedLoginAttempts; + + // Audit + @Schema(description = "Raison de la dernière modification") + private String raisonModification; + + @Schema(description = "Commentaires administratifs") + private String commentaires; + + /** + * Retourne le nom complet de l'utilisateur + * @return prénom + nom + */ + public String getNomComplet() { + if (prenom != null && nom != null) { + return prenom + " " + nom; + } + return username; + } + + /** + * Détermine si l'utilisateur est actif + * @return true si statut ACTIF et enabled + */ + public boolean isActif() { + return statut == StatutUser.ACTIF && Boolean.TRUE.equals(enabled); + } + + /** + * Détermine si le compte a expiré + * @return true si dateExpiration est passée + */ + public boolean isExpire() { + return dateExpiration != null && dateExpiration.isBefore(LocalDateTime.now()); + } + + /** + * Détermine si l'utilisateur a des actions requises + * @return true si des actions sont requises + */ + public boolean hasRequiredActions() { + return requiredActions != null && !requiredActions.isEmpty(); + } + + /** + * DTO pour identité fédérée + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @SuperBuilder + @Schema(description = "Identité fédérée") + public static class FederatedIdentityDTO { + @Schema(description = "Fournisseur d'identité", example = "google") + private String identityProvider; + + @Schema(description = "ID utilisateur chez le fournisseur") + private String userId; + + @Schema(description = "Nom d'utilisateur chez le fournisseur") + private String userName; + } +} diff --git a/src/main/java/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO.java b/src/main/java/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO.java new file mode 100644 index 0000000..429e68a --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO.java @@ -0,0 +1,190 @@ +package dev.lions.user.manager.dto.user; + +import com.fasterxml.jackson.annotation.JsonInclude; +import dev.lions.user.manager.enums.user.StatutUser; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * Critères de recherche pour les utilisateurs + * Utilisé pour filtrer les utilisateurs via l'API Keycloak Admin + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Critères de recherche d'utilisateurs") +public class UserSearchCriteriaDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + // Recherche textuelle + @Schema(description = "Terme de recherche générale (username, email, nom, prénom)", example = "dupont") + private String searchTerm; + + @Schema(description = "Nom d'utilisateur exact", example = "jdupont") + private String username; + + @Schema(description = "Email exact", example = "jean.dupont@lions.dev") + private String email; + + @Schema(description = "Prénom", example = "Jean") + private String prenom; + + @Schema(description = "Nom de famille", example = "Dupont") + private String nom; + + // Filtres de statut + @Schema(description = "Statut de l'utilisateur", example = "ACTIF") + private StatutUser statut; + + @Schema(description = "Compte activé", example = "true") + private Boolean enabled; + + @Schema(description = "Email vérifié", example = "true") + private Boolean emailVerified; + + // Filtres de rôle et groupe + @Schema(description = "Liste des rôles Realm à filtrer") + private List realmRoles; + + @Schema(description = "Liste des rôles Client à filtrer") + private List clientRoles; + + @Schema(description = "Liste des groupes à filtrer") + private List groups; + + @Schema(description = "Nom du client pour filtrer par rôles client", example = "btpxpress-app") + private String clientName; + + // Filtres organisationnels + @Schema(description = "Organisation/Entreprise", example = "Lions Dev") + private String organisation; + + @Schema(description = "Département", example = "IT") + private String departement; + + @Schema(description = "Fonction/Poste", example = "Développeur") + private String fonction; + + @Schema(description = "Pays", example = "Côte d'Ivoire") + private String pays; + + @Schema(description = "Ville", example = "Abidjan") + private String ville; + + // Filtres temporels + @Schema(description = "Date de création minimum", example = "2025-01-01T00:00:00") + private LocalDateTime dateCreationMin; + + @Schema(description = "Date de création maximum", example = "2025-12-31T23:59:59") + private LocalDateTime dateCreationMax; + + @Schema(description = "Date de dernière connexion minimum", example = "2025-01-01T00:00:00") + private LocalDateTime derniereConnexionMin; + + @Schema(description = "Date de dernière connexion maximum", example = "2025-01-31T23:59:59") + private LocalDateTime derniereConnexionMax; + + // Filtres spéciaux + @Schema(description = "Utilisateurs avec actions requises uniquement", example = "true") + private Boolean hasRequiredActions; + + @Schema(description = "Utilisateurs verrouillés uniquement", example = "false") + private Boolean isLocked; + + @Schema(description = "Utilisateurs expirés uniquement", example = "false") + private Boolean isExpired; + + @Schema(description = "Utilisateurs avec sessions actives uniquement", example = "true") + private Boolean hasActiveSessions; + + // Realm + @Schema(description = "Nom du Realm à filtrer", example = "btpxpress") + private String realmName; + + // Pagination + @Schema(description = "Numéro de page (commence à 0)", example = "0", defaultValue = "0") + @Builder.Default + private Integer page = 0; + + @Schema(description = "Taille de la page", example = "20", defaultValue = "20") + @Builder.Default + private Integer pageSize = 20; + + @Schema(description = "Nombre maximum de résultats", example = "100") + private Integer maxResults; + + // Tri + @Schema(description = "Champ de tri (username, email, prenom, nom, dateCreation, derniereConnexion)", example = "username") + @Builder.Default + private String sortBy = "username"; + + @Schema(description = "Ordre de tri (ASC ou DESC)", example = "ASC") + @Builder.Default + private String sortOrder = "ASC"; + + // Options d'inclusion + @Schema(description = "Inclure les rôles dans les résultats", example = "true") + @Builder.Default + private Boolean includeRoles = false; + + @Schema(description = "Inclure les groupes dans les résultats", example = "true") + @Builder.Default + private Boolean includeGroups = false; + + @Schema(description = "Inclure les attributs personnalisés", example = "false") + @Builder.Default + private Boolean includeAttributes = false; + + @Schema(description = "Inclure les informations de session", example = "false") + @Builder.Default + private Boolean includeSessionInfo = false; + + /** + * Détermine si des filtres de recherche sont appliqués + * @return true si au moins un filtre est défini + */ + public boolean hasFilters() { + return searchTerm != null + || username != null + || email != null + || prenom != null + || nom != null + || statut != null + || enabled != null + || emailVerified != null + || (realmRoles != null && !realmRoles.isEmpty()) + || (clientRoles != null && !clientRoles.isEmpty()) + || (groups != null && !groups.isEmpty()) + || organisation != null + || departement != null + || fonction != null + || pays != null + || ville != null + || dateCreationMin != null + || dateCreationMax != null + || derniereConnexionMin != null + || derniereConnexionMax != null + || hasRequiredActions != null + || isLocked != null + || isExpired != null + || hasActiveSessions != null; + } + + /** + * Calcule l'offset pour la pagination Keycloak + * @return offset calculé à partir de page et pageSize + */ + public int getOffset() { + return page * pageSize; + } +} diff --git a/src/main/java/dev/lions/user/manager/dto/user/UserSearchResultDTO.java b/src/main/java/dev/lions/user/manager/dto/user/UserSearchResultDTO.java new file mode 100644 index 0000000..150681b --- /dev/null +++ b/src/main/java/dev/lions/user/manager/dto/user/UserSearchResultDTO.java @@ -0,0 +1,105 @@ +package dev.lions.user.manager.dto.user; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.io.Serializable; +import java.util.List; + +/** + * Résultat paginé de recherche d'utilisateurs + * Contient la liste des utilisateurs et les métadonnées de pagination + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Résultat paginé de recherche d'utilisateurs") +public class UserSearchResultDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "Liste des utilisateurs trouvés") + private List users; + + @Schema(description = "Nombre total d'utilisateurs correspondant aux critères", example = "156") + private Long totalCount; + + @Schema(description = "Numéro de la page actuelle (commence à 0)", example = "0") + private Integer currentPage; + + @Schema(description = "Taille de la page", example = "20") + private Integer pageSize; + + @Schema(description = "Nombre total de pages", example = "8") + private Integer totalPages; + + @Schema(description = "Indique s'il y a une page suivante", example = "true") + private Boolean hasNextPage; + + @Schema(description = "Indique s'il y a une page précédente", example = "false") + private Boolean hasPreviousPage; + + @Schema(description = "Index du premier élément de la page", example = "0") + private Integer firstElement; + + @Schema(description = "Index du dernier élément de la page", example = "19") + private Integer lastElement; + + @Schema(description = "Indique si la page est vide", example = "false") + private Boolean isEmpty; + + @Schema(description = "Indique si c'est la première page", example = "true") + private Boolean isFirstPage; + + @Schema(description = "Indique si c'est la dernière page", example = "false") + private Boolean isLastPage; + + @Schema(description = "Critères de recherche utilisés") + private UserSearchCriteriaDTO criteria; + + @Schema(description = "Temps d'exécution de la recherche en millisecondes", example = "145") + private Long executionTimeMs; + + /** + * Construit un résultat de recherche à partir d'une liste d'utilisateurs + * @param users liste des utilisateurs + * @param criteria critères de recherche + * @param totalCount nombre total de résultats + * @return UserSearchResultDTO + */ + public static UserSearchResultDTO of(List users, UserSearchCriteriaDTO criteria, Long totalCount) { + int pageSize = criteria.getPageSize(); + int currentPage = criteria.getPage(); + long totalPages = (totalCount + pageSize - 1) / pageSize; + + return UserSearchResultDTO.builder() + .users(users) + .totalCount(totalCount) + .currentPage(currentPage) + .pageSize(pageSize) + .totalPages((int) totalPages) + .hasNextPage(currentPage < totalPages - 1) + .hasPreviousPage(currentPage > 0) + .firstElement(currentPage * pageSize) + .lastElement(Math.min((currentPage + 1) * pageSize - 1, totalCount.intValue())) + .isEmpty(users == null || users.isEmpty()) + .isFirstPage(currentPage == 0) + .isLastPage(currentPage >= totalPages - 1) + .criteria(criteria) + .build(); + } + + /** + * Retourne le nombre d'utilisateurs dans la page courante + * @return nombre d'utilisateurs + */ + public int getCurrentPageSize() { + return users != null ? users.size() : 0; + } +} diff --git a/src/main/java/dev/lions/user/manager/enums/audit/TypeActionAudit.java b/src/main/java/dev/lions/user/manager/enums/audit/TypeActionAudit.java new file mode 100644 index 0000000..add7505 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/enums/audit/TypeActionAudit.java @@ -0,0 +1,108 @@ +package dev.lions.user.manager.enums.audit; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +/** + * Type d'action effectuée sur une ressource + * Utilisé pour l'audit trail + */ +@Getter +@RequiredArgsConstructor +@Schema(description = "Type d'action pour l'audit") +public enum TypeActionAudit { + + // Actions Utilisateur + USER_CREATE("Création utilisateur", "USER", "CREATE"), + USER_UPDATE("Modification utilisateur", "USER", "UPDATE"), + USER_DELETE("Suppression utilisateur", "USER", "DELETE"), + USER_ACTIVATE("Activation utilisateur", "USER", "ACTIVATE"), + USER_DEACTIVATE("Désactivation utilisateur", "USER", "DEACTIVATE"), + USER_SUSPEND("Suspension utilisateur", "USER", "SUSPEND"), + USER_UNLOCK("Déverrouillage utilisateur", "USER", "UNLOCK"), + USER_PASSWORD_RESET("Réinitialisation mot de passe", "USER", "PASSWORD_RESET"), + USER_EMAIL_VERIFY("Vérification email", "USER", "EMAIL_VERIFY"), + USER_FORCE_LOGOUT("Déconnexion forcée", "USER", "FORCE_LOGOUT"), + + // Actions Rôle + ROLE_CREATE("Création rôle", "ROLE", "CREATE"), + ROLE_UPDATE("Modification rôle", "ROLE", "UPDATE"), + ROLE_DELETE("Suppression rôle", "ROLE", "DELETE"), + ROLE_ASSIGN("Attribution rôle", "ROLE", "ASSIGN"), + ROLE_REVOKE("Révocation rôle", "ROLE", "REVOKE"), + ROLE_ADD_COMPOSITE("Ajout rôle composite", "ROLE", "ADD_COMPOSITE"), + ROLE_REMOVE_COMPOSITE("Retrait rôle composite", "ROLE", "REMOVE_COMPOSITE"), + + // Actions Groupe + GROUP_CREATE("Création groupe", "GROUP", "CREATE"), + GROUP_UPDATE("Modification groupe", "GROUP", "UPDATE"), + GROUP_DELETE("Suppression groupe", "GROUP", "DELETE"), + GROUP_ADD_MEMBER("Ajout membre groupe", "GROUP", "ADD_MEMBER"), + GROUP_REMOVE_MEMBER("Retrait membre groupe", "GROUP", "REMOVE_MEMBER"), + + // Actions Realm + REALM_SYNC("Synchronisation realm", "REALM", "SYNC"), + REALM_EXPORT("Export realm", "REALM", "EXPORT"), + REALM_IMPORT("Import realm", "REALM", "IMPORT"), + + // Actions Session + SESSION_CREATE("Création session", "SESSION", "CREATE"), + SESSION_DELETE("Suppression session", "SESSION", "DELETE"), + SESSION_REVOKE_ALL("Révocation toutes sessions", "SESSION", "REVOKE_ALL"), + + // Actions Système + SYSTEM_BACKUP("Sauvegarde système", "SYSTEM", "BACKUP"), + SYSTEM_RESTORE("Restauration système", "SYSTEM", "RESTORE"), + SYSTEM_CONFIG_CHANGE("Modification configuration", "SYSTEM", "CONFIG_CHANGE"); + + private final String libelle; + private final String ressourceType; + private final String actionType; + + /** + * Détermine si l'action concerne un utilisateur + */ + public boolean isUserAction() { + return ressourceType.equals("USER"); + } + + /** + * Détermine si l'action concerne un rôle + */ + public boolean isRoleAction() { + return ressourceType.equals("ROLE"); + } + + /** + * Détermine si l'action est une création + */ + public boolean isCreateAction() { + return actionType.equals("CREATE"); + } + + /** + * Détermine si l'action est une modification + */ + public boolean isUpdateAction() { + return actionType.equals("UPDATE"); + } + + /** + * Détermine si l'action est une suppression + */ + public boolean isDeleteAction() { + return actionType.equals("DELETE"); + } + + /** + * Détermine si l'action est critique (nécessite alerte) + */ + public boolean isCritical() { + return this == USER_DELETE + || this == ROLE_DELETE + || this == USER_SUSPEND + || this == SESSION_REVOKE_ALL + || this == SYSTEM_RESTORE; + } +} diff --git a/src/main/java/dev/lions/user/manager/enums/role/TypeRole.java b/src/main/java/dev/lions/user/manager/enums/role/TypeRole.java new file mode 100644 index 0000000..d1cc603 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/enums/role/TypeRole.java @@ -0,0 +1,60 @@ +package dev.lions.user.manager.enums.role; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +/** + * Type de rôle dans Keycloak + * Distingue les rôles au niveau Realm vs Client + */ +@Getter +@RequiredArgsConstructor +@Schema(description = "Type de rôle Keycloak") +public enum TypeRole { + + /** + * Rôle global au niveau du Realm + * Applicable à tous les clients du realm + */ + REALM_ROLE("Realm Role", "Rôle global applicable à tous les clients du realm", "realm-role"), + + /** + * Rôle spécifique à un client + * Limité au scope d'un client particulier + */ + CLIENT_ROLE("Client Role", "Rôle spécifique à un client particulier", "client-role"), + + /** + * Rôle composite (contient d'autres rôles) + */ + COMPOSITE_ROLE("Composite Role", "Rôle composite contenant d'autres rôles", "composite-role"); + + private final String libelle; + private final String description; + private final String codeKeycloak; + + /** + * Détermine si le rôle est au niveau realm + * @return true si c'est un realm role + */ + public boolean isRealmRole() { + return this == REALM_ROLE; + } + + /** + * Détermine si le rôle est au niveau client + * @return true si c'est un client role + */ + public boolean isClientRole() { + return this == CLIENT_ROLE; + } + + /** + * Détermine si le rôle est composite + * @return true si c'est un composite role + */ + public boolean isComposite() { + return this == COMPOSITE_ROLE; + } +} diff --git a/src/main/java/dev/lions/user/manager/enums/user/StatutUser.java b/src/main/java/dev/lions/user/manager/enums/user/StatutUser.java new file mode 100644 index 0000000..bcf0834 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/enums/user/StatutUser.java @@ -0,0 +1,79 @@ +package dev.lions.user.manager.enums.user; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +/** + * Statut d'un utilisateur dans Keycloak + * Mappé depuis le champ "enabled" et attributs personnalisés + */ +@Getter +@RequiredArgsConstructor +@Schema(description = "Statut d'un utilisateur") +public enum StatutUser { + + /** + * Utilisateur actif et opérationnel + */ + ACTIF("Actif", "Utilisateur actif avec accès complet", true), + + /** + * Utilisateur désactivé temporairement (peut être réactivé) + */ + INACTIF("Inactif", "Utilisateur désactivé temporairement", false), + + /** + * Utilisateur suspendu suite à une action administrative + */ + SUSPENDU("Suspendu", "Compte suspendu par un administrateur", false), + + /** + * Utilisateur en attente de validation + */ + EN_ATTENTE("En attente", "Compte en attente de validation", false), + + /** + * Utilisateur verrouillé suite à des tentatives échouées + */ + VERROUILLE("Verrouillé", "Compte verrouillé suite à plusieurs échecs d'authentification", false), + + /** + * Utilisateur dont le compte a expiré + */ + EXPIRE("Expiré", "Compte expiré et nécessite une réactivation", false), + + /** + * Utilisateur supprimé (soft delete) + */ + SUPPRIME("Supprimé", "Compte supprimé logiquement", false); + + private final String libelle; + private final String description; + private final boolean enabled; + + /** + * Convertit un statut Keycloak "enabled" en StatutUser + * @param enabled état enabled de Keycloak + * @return ACTIF si enabled=true, INACTIF sinon + */ + public static StatutUser fromEnabled(boolean enabled) { + return enabled ? ACTIF : INACTIF; + } + + /** + * Détermine si l'utilisateur peut se connecter + * @return true si le statut permet la connexion + */ + public boolean peutSeConnecter() { + return this == ACTIF; + } + + /** + * Détermine si l'utilisateur peut être réactivé + * @return true si le statut permet la réactivation + */ + public boolean peutEtreReactive() { + return this == INACTIF || this == SUSPENDU || this == EXPIRE; + } +} diff --git a/src/main/java/dev/lions/user/manager/service/AuditService.java b/src/main/java/dev/lions/user/manager/service/AuditService.java new file mode 100644 index 0000000..ee6d729 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/service/AuditService.java @@ -0,0 +1,219 @@ +package dev.lions.user.manager.service; + +import dev.lions.user.manager.dto.audit.AuditLogDTO; +import dev.lions.user.manager.enums.audit.TypeActionAudit; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * Service de gestion des logs d'audit + * Enregistre toutes les actions effectuées via l'API + */ +public interface AuditService { + + /** + * Enregistre une entrée d'audit + * @param auditLog entrée d'audit + * @return entrée enregistrée avec son ID + */ + AuditLogDTO logAction(@Valid @NotNull AuditLogDTO auditLog); + + /** + * Enregistre une action réussie + * @param typeAction type d'action + * @param ressourceType type de ressource + * @param ressourceId ID de la ressource + * @param ressourceName nom de la ressource + * @param realmName nom du realm + * @param acteurUserId ID de l'acteur + * @param description description + */ + void logSuccess(@NotNull TypeActionAudit typeAction, + @NotBlank String ressourceType, + String ressourceId, + String ressourceName, + @NotBlank String realmName, + @NotBlank String acteurUserId, + String description); + + /** + * Enregistre une action échouée + * @param typeAction type d'action + * @param ressourceType type de ressource + * @param ressourceId ID de la ressource + * @param ressourceName nom de la ressource + * @param realmName nom du realm + * @param acteurUserId ID de l'acteur + * @param errorCode code d'erreur + * @param errorMessage message d'erreur + */ + void logFailure(@NotNull TypeActionAudit typeAction, + @NotBlank String ressourceType, + String ressourceId, + String ressourceName, + @NotBlank String realmName, + @NotBlank String acteurUserId, + String errorCode, + String errorMessage); + + /** + * Recherche les logs d'audit par utilisateur acteur + * @param acteurUserId ID de l'utilisateur acteur + * @param dateDebut date de début + * @param dateFin date de fin + * @param page numéro de page + * @param pageSize taille de la page + * @return liste des logs + */ + List findByActeur(@NotBlank String acteurUserId, + LocalDateTime dateDebut, + LocalDateTime dateFin, + int page, + int pageSize); + + /** + * Recherche les logs d'audit par ressource + * @param ressourceType type de ressource + * @param ressourceId ID de la ressource + * @param dateDebut date de début + * @param dateFin date de fin + * @param page numéro de page + * @param pageSize taille de la page + * @return liste des logs + */ + List findByRessource(@NotBlank String ressourceType, + @NotBlank String ressourceId, + LocalDateTime dateDebut, + LocalDateTime dateFin, + int page, + int pageSize); + + /** + * Recherche les logs d'audit par type d'action + * @param typeAction type d'action + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @param page numéro de page + * @param pageSize taille de la page + * @return liste des logs + */ + List findByTypeAction(@NotNull TypeActionAudit typeAction, + @NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin, + int page, + int pageSize); + + /** + * Recherche les logs d'audit par realm + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @param page numéro de page + * @param pageSize taille de la page + * @return liste des logs + */ + List findByRealm(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin, + int page, + int pageSize); + + /** + * Recherche les actions échouées + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @param page numéro de page + * @param pageSize taille de la page + * @return liste des logs d'échec + */ + List findFailures(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin, + int page, + int pageSize); + + /** + * Recherche les actions critiques + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @param page numéro de page + * @param pageSize taille de la page + * @return liste des logs critiques + */ + List findCriticalActions(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin, + int page, + int pageSize); + + /** + * Compte les actions par type + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @return map type d'action -> nombre + */ + Map countByActionType(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin); + + /** + * Compte les actions par utilisateur + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @return map username -> nombre d'actions + */ + Map countByActeur(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin); + + /** + * Compte les actions réussies vs échouées + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @return map "success" -> count, "failure" -> count + */ + Map countSuccessVsFailure(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin); + + /** + * Exporte les logs d'audit au format CSV + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @return contenu CSV + */ + String exportToCSV(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin); + + /** + * Supprime les logs d'audit plus anciens qu'une date + * @param dateLimite date limite (logs antérieurs seront supprimés) + * @return nombre de logs supprimés + */ + long purgeOldLogs(@NotNull LocalDateTime dateLimite); + + /** + * Récupère les statistiques d'audit pour un dashboard + * @param realmName nom du realm + * @param dateDebut date de début + * @param dateFin date de fin + * @return map de statistiques + */ + Map getAuditStatistics(@NotBlank String realmName, + LocalDateTime dateDebut, + LocalDateTime dateFin); +} diff --git a/src/main/java/dev/lions/user/manager/service/RoleService.java b/src/main/java/dev/lions/user/manager/service/RoleService.java new file mode 100644 index 0000000..b38d361 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/service/RoleService.java @@ -0,0 +1,226 @@ +package dev.lions.user.manager.service; + +import dev.lions.user.manager.dto.role.RoleAssignmentDTO; +import dev.lions.user.manager.dto.role.RoleDTO; +import dev.lions.user.manager.enums.role.TypeRole; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import java.util.List; +import java.util.Optional; + +/** + * Service de gestion des rôles Keycloak + * Utilise uniquement l'API Admin Keycloak (AUCUN accès direct à la DB) + */ +public interface RoleService { + + /** + * Récupère tous les rôles d'un realm + * @param realmName nom du realm + * @return liste des rôles + */ + List getAllRealmRoles(@NotBlank String realmName); + + /** + * Récupère tous les rôles d'un client + * @param realmName nom du realm + * @param clientName nom du client + * @return liste des rôles + */ + List getAllClientRoles(@NotBlank String realmName, @NotBlank String clientName); + + /** + * Récupère un rôle par son ID + * @param roleId ID du rôle + * @param realmName nom du realm + * @param typeRole type de rôle (REALM ou CLIENT) + * @param clientName nom du client (si CLIENT_ROLE) + * @return rôle ou Optional vide + */ + Optional getRoleById(@NotBlank String roleId, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Récupère un rôle par son nom + * @param roleName nom du rôle + * @param realmName nom du realm + * @param typeRole type de rôle (REALM ou CLIENT) + * @param clientName nom du client (si CLIENT_ROLE) + * @return rôle ou Optional vide + */ + Optional getRoleByName(@NotBlank String roleName, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Crée un nouveau rôle realm + * @param role données du rôle + * @param realmName nom du realm + * @return rôle créé + */ + RoleDTO createRealmRole(@Valid @NotNull RoleDTO role, @NotBlank String realmName); + + /** + * Crée un nouveau rôle client + * @param role données du rôle + * @param realmName nom du realm + * @param clientName nom du client + * @return rôle créé + */ + RoleDTO createClientRole(@Valid @NotNull RoleDTO role, + @NotBlank String realmName, + @NotBlank String clientName); + + /** + * Met à jour un rôle + * @param roleId ID du rôle + * @param role données modifiées + * @param realmName nom du realm + * @param typeRole type de rôle + * @param clientName nom du client (si CLIENT_ROLE) + * @return rôle mis à jour + */ + RoleDTO updateRole(@NotBlank String roleId, + @Valid @NotNull RoleDTO role, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Supprime un rôle + * @param roleId ID du rôle + * @param realmName nom du realm + * @param typeRole type de rôle + * @param clientName nom du client (si CLIENT_ROLE) + */ + void deleteRole(@NotBlank String roleId, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Assigne des rôles à un utilisateur + * @param assignment données d'attribution + */ + void assignRolesToUser(@Valid @NotNull RoleAssignmentDTO assignment); + + /** + * Révoque des rôles d'un utilisateur + * @param assignment données de révocation + */ + void revokeRolesFromUser(@Valid @NotNull RoleAssignmentDTO assignment); + + /** + * Récupère les rôles realm d'un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @return liste des rôles + */ + List getUserRealmRoles(@NotBlank String userId, @NotBlank String realmName); + + /** + * Récupère les rôles client d'un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @param clientName nom du client + * @return liste des rôles + */ + List getUserClientRoles(@NotBlank String userId, + @NotBlank String realmName, + @NotBlank String clientName); + + /** + * Récupère tous les rôles d'un utilisateur (realm + clients) + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @return liste des rôles + */ + List getAllUserRoles(@NotBlank String userId, @NotBlank String realmName); + + /** + * Ajoute un rôle composite + * @param parentRoleId ID du rôle parent + * @param childRoleIds IDs des rôles enfants à ajouter + * @param realmName nom du realm + * @param typeRole type du rôle parent + * @param clientName nom du client (si CLIENT_ROLE) + */ + void addCompositeRoles(@NotBlank String parentRoleId, + @NotNull List childRoleIds, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Retire un rôle composite + * @param parentRoleId ID du rôle parent + * @param childRoleIds IDs des rôles enfants à retirer + * @param realmName nom du realm + * @param typeRole type du rôle parent + * @param clientName nom du client (si CLIENT_ROLE) + */ + void removeCompositeRoles(@NotBlank String parentRoleId, + @NotNull List childRoleIds, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Récupère les rôles composites d'un rôle + * @param roleId ID du rôle + * @param realmName nom du realm + * @param typeRole type de rôle + * @param clientName nom du client (si CLIENT_ROLE) + * @return liste des rôles composites + */ + List getCompositeRoles(@NotBlank String roleId, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Compte le nombre d'utilisateurs ayant un rôle + * @param roleId ID du rôle + * @param realmName nom du realm + * @param typeRole type de rôle + * @param clientName nom du client (si CLIENT_ROLE) + * @return nombre d'utilisateurs + */ + long countUsersWithRole(@NotBlank String roleId, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Vérifie si un rôle existe + * @param roleName nom du rôle + * @param realmName nom du realm + * @param typeRole type de rôle + * @param clientName nom du client (si CLIENT_ROLE) + * @return true si existe + */ + boolean roleExists(@NotBlank String roleName, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); + + /** + * Vérifie si un utilisateur a un rôle spécifique + * @param userId ID de l'utilisateur + * @param roleName nom du rôle + * @param realmName nom du realm + * @param typeRole type de rôle + * @param clientName nom du client (si CLIENT_ROLE) + * @return true si l'utilisateur a le rôle + */ + boolean userHasRole(@NotBlank String userId, + @NotBlank String roleName, + @NotBlank String realmName, + @NotNull TypeRole typeRole, + String clientName); +} diff --git a/src/main/java/dev/lions/user/manager/service/SyncService.java b/src/main/java/dev/lions/user/manager/service/SyncService.java new file mode 100644 index 0000000..b0cfb91 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/service/SyncService.java @@ -0,0 +1,65 @@ +package dev.lions.user.manager.service; + +import jakarta.validation.constraints.NotBlank; + +import java.util.Map; + +/** + * Service de synchronisation avec Keycloak + * Permet la synchronisation des données entre différents realms + */ +public interface SyncService { + + /** + * Synchronise les utilisateurs d'un realm + * @param realmName nom du realm à synchroniser + * @return nombre d'utilisateurs synchronisés + */ + int syncUsersFromRealm(@NotBlank String realmName); + + /** + * Synchronise les rôles d'un realm + * @param realmName nom du realm à synchroniser + * @return nombre de rôles synchronisés + */ + int syncRolesFromRealm(@NotBlank String realmName); + + /** + * Synchronise tous les realms configurés + * @return map realm -> nombre d'éléments synchronisés + */ + Map syncAllRealms(); + + /** + * Vérifie la cohérence des données entre cache local et Keycloak + * @param realmName nom du realm + * @return rapport de cohérence + */ + Map checkDataConsistency(@NotBlank String realmName); + + /** + * Force la resynchronisation complète d'un realm + * @param realmName nom du realm + * @return statistiques de synchronisation + */ + Map forceSyncRealm(@NotBlank String realmName); + + /** + * Récupère le statut de la dernière synchronisation + * @param realmName nom du realm + * @return statut de synchronisation + */ + Map getLastSyncStatus(@NotBlank String realmName); + + /** + * Vérifie la disponibilité de Keycloak + * @return true si Keycloak est disponible + */ + boolean isKeycloakAvailable(); + + /** + * Récupère les informations de santé de Keycloak + * @return informations de santé + */ + Map getKeycloakHealthInfo(); +} diff --git a/src/main/java/dev/lions/user/manager/service/UserService.java b/src/main/java/dev/lions/user/manager/service/UserService.java new file mode 100644 index 0000000..acbce8b --- /dev/null +++ b/src/main/java/dev/lions/user/manager/service/UserService.java @@ -0,0 +1,185 @@ +package dev.lions.user.manager.service; + +import dev.lions.user.manager.dto.user.UserDTO; +import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO; +import dev.lions.user.manager.dto.user.UserSearchResultDTO; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import java.util.List; +import java.util.Optional; + +/** + * Service de gestion des utilisateurs Keycloak + * Utilise uniquement l'API Admin Keycloak (AUCUN accès direct à la DB) + */ +public interface UserService { + + /** + * Recherche des utilisateurs selon des critères + * @param criteria critères de recherche + * @return résultat paginé + */ + UserSearchResultDTO searchUsers(@Valid @NotNull UserSearchCriteriaDTO criteria); + + /** + * Récupère un utilisateur par son ID + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @return utilisateur ou Optional vide + */ + Optional getUserById(@NotBlank String userId, @NotBlank String realmName); + + /** + * Récupère un utilisateur par son username + * @param username username + * @param realmName nom du realm + * @return utilisateur ou Optional vide + */ + Optional getUserByUsername(@NotBlank String username, @NotBlank String realmName); + + /** + * Récupère un utilisateur par son email + * @param email email + * @param realmName nom du realm + * @return utilisateur ou Optional vide + */ + Optional getUserByEmail(@NotBlank String email, @NotBlank String realmName); + + /** + * Crée un nouvel utilisateur + * @param user données de l'utilisateur + * @param realmName nom du realm + * @return utilisateur créé avec son ID + */ + UserDTO createUser(@Valid @NotNull UserDTO user, @NotBlank String realmName); + + /** + * Met à jour un utilisateur existant + * @param userId ID de l'utilisateur + * @param user données modifiées + * @param realmName nom du realm + * @return utilisateur mis à jour + */ + UserDTO updateUser(@NotBlank String userId, @Valid @NotNull UserDTO user, @NotBlank String realmName); + + /** + * Supprime un utilisateur (soft ou hard delete selon configuration) + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @param hardDelete true pour suppression définitive, false pour soft delete + */ + void deleteUser(@NotBlank String userId, @NotBlank String realmName, boolean hardDelete); + + /** + * Active un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + */ + void activateUser(@NotBlank String userId, @NotBlank String realmName); + + /** + * Désactive un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @param raison raison de la désactivation + */ + void deactivateUser(@NotBlank String userId, @NotBlank String realmName, String raison); + + /** + * Suspend un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @param raison raison de la suspension + * @param duree durée de la suspension en jours (0 = indéfinie) + */ + void suspendUser(@NotBlank String userId, @NotBlank String realmName, String raison, int duree); + + /** + * Déverrouille un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + */ + void unlockUser(@NotBlank String userId, @NotBlank String realmName); + + /** + * Réinitialise le mot de passe d'un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @param temporaryPassword mot de passe temporaire + * @param temporary true si le mot de passe doit être changé à la prochaine connexion + */ + void resetPassword(@NotBlank String userId, @NotBlank String realmName, + @NotBlank String temporaryPassword, boolean temporary); + + /** + * Envoie un email de vérification + * @param userId ID de l'utilisateur + * @param realmName nom du realm + */ + void sendVerificationEmail(@NotBlank String userId, @NotBlank String realmName); + + /** + * Force la déconnexion de toutes les sessions d'un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @return nombre de sessions révoquées + */ + int logoutAllSessions(@NotBlank String userId, @NotBlank String realmName); + + /** + * Récupère les sessions actives d'un utilisateur + * @param userId ID de l'utilisateur + * @param realmName nom du realm + * @return liste des informations de session + */ + List getActiveSessions(@NotBlank String userId, @NotBlank String realmName); + + /** + * Compte le nombre d'utilisateurs selon des critères + * @param criteria critères de recherche + * @return nombre d'utilisateurs + */ + long countUsers(@NotNull UserSearchCriteriaDTO criteria); + + /** + * Récupère tous les utilisateurs d'un realm (avec pagination) + * @param realmName nom du realm + * @param page numéro de page + * @param pageSize taille de la page + * @return liste paginée d'utilisateurs + */ + UserSearchResultDTO getAllUsers(@NotBlank String realmName, int page, int pageSize); + + /** + * Vérifie si un username existe déjà + * @param username username à vérifier + * @param realmName nom du realm + * @return true si existe + */ + boolean usernameExists(@NotBlank String username, @NotBlank String realmName); + + /** + * Vérifie si un email existe déjà + * @param email email à vérifier + * @param realmName nom du realm + * @return true si existe + */ + boolean emailExists(@NotBlank String email, @NotBlank String realmName); + + /** + * Exporte les utilisateurs au format CSV + * @param criteria critères de recherche + * @return contenu CSV + */ + String exportUsersToCSV(@NotNull UserSearchCriteriaDTO criteria); + + /** + * Importe des utilisateurs depuis un CSV + * @param csvContent contenu CSV + * @param realmName nom du realm + * @return nombre d'utilisateurs importés + */ + int importUsersFromCSV(@NotBlank String csvContent, @NotBlank String realmName); +} diff --git a/src/main/java/dev/lions/user/manager/validation/ValidationConstants.java b/src/main/java/dev/lions/user/manager/validation/ValidationConstants.java new file mode 100644 index 0000000..54b007d --- /dev/null +++ b/src/main/java/dev/lions/user/manager/validation/ValidationConstants.java @@ -0,0 +1,72 @@ +package dev.lions.user.manager.validation; + +/** + * Constantes de validation pour les DTOs + * Centralise les règles de validation communes + */ +public final class ValidationConstants { + + private ValidationConstants() { + // Classe utilitaire, pas d'instanciation + } + + // Username + public static final int USERNAME_MIN_LENGTH = 3; + public static final int USERNAME_MAX_LENGTH = 100; + public static final String USERNAME_PATTERN = "^[a-zA-Z0-9._-]+$"; + public static final String USERNAME_PATTERN_MESSAGE = "Le nom d'utilisateur ne peut contenir que des lettres, chiffres, points, tirets et underscores"; + + // Email + public static final String EMAIL_PATTERN = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"; + public static final String EMAIL_PATTERN_MESSAGE = "Format d'email invalide"; + + // Nom et Prénom + public static final int NAME_MIN_LENGTH = 2; + public static final int NAME_MAX_LENGTH = 100; + public static final String NAME_PATTERN = "^[a-zA-ZÀ-ÿ\\s'-]+$"; + public static final String NAME_PATTERN_MESSAGE = "Le nom ne peut contenir que des lettres, espaces, apostrophes et tirets"; + + // Téléphone + public static final String PHONE_PATTERN = "^\\+?[0-9\\s.-]{8,20}$"; + public static final String PHONE_PATTERN_MESSAGE = "Format de téléphone invalide"; + + // Mot de passe + public static final int PASSWORD_MIN_LENGTH = 8; + public static final int PASSWORD_MAX_LENGTH = 100; + public static final String PASSWORD_PATTERN = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; + public static final String PASSWORD_PATTERN_MESSAGE = "Le mot de passe doit contenir au moins 8 caractères, une majuscule, une minuscule, un chiffre et un caractère spécial"; + + // Role + public static final int ROLE_NAME_MIN_LENGTH = 2; + public static final int ROLE_NAME_MAX_LENGTH = 100; + public static final String ROLE_NAME_PATTERN = "^[a-zA-Z0-9_-]+$"; + public static final String ROLE_NAME_PATTERN_MESSAGE = "Le nom du rôle ne peut contenir que des lettres, chiffres, underscores et tirets"; + + // Realm + public static final String REALM_NAME_PATTERN = "^[a-zA-Z0-9_-]+$"; + public static final String REALM_NAME_PATTERN_MESSAGE = "Le nom du realm ne peut contenir que des lettres, chiffres, underscores et tirets"; + + // UUID + public static final String UUID_PATTERN = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"; + public static final String UUID_PATTERN_MESSAGE = "Format UUID invalide"; + + // Messages d'erreur génériques + public static final String REQUIRED_FIELD = "Ce champ est obligatoire"; + public static final String INVALID_FORMAT = "Format invalide"; + public static final String TOO_SHORT = "Valeur trop courte"; + public static final String TOO_LONG = "Valeur trop longue"; + + // Pagination + public static final int DEFAULT_PAGE_SIZE = 20; + public static final int MAX_PAGE_SIZE = 100; + public static final int MIN_PAGE_SIZE = 1; + + // Audit + public static final int MAX_DESCRIPTION_LENGTH = 500; + public static final int MAX_COMMENT_LENGTH = 1000; + public static final int MAX_ERROR_MESSAGE_LENGTH = 2000; + + // IP Address + public static final String IP_ADDRESS_PATTERN = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"; + public static final String IP_ADDRESS_PATTERN_MESSAGE = "Format d'adresse IP invalide"; +} diff --git a/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO$AuditLogDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO$AuditLogDTOBuilder.class new file mode 100644 index 0000000..312e69f Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO$AuditLogDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO$AuditLogDTOBuilderImpl.class b/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO$AuditLogDTOBuilderImpl.class new file mode 100644 index 0000000..a2dd22b Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO$AuditLogDTOBuilderImpl.class differ diff --git a/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO.class b/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO.class new file mode 100644 index 0000000..7bef7fc Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/audit/AuditLogDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/base/BaseDTO$BaseDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/base/BaseDTO$BaseDTOBuilder.class new file mode 100644 index 0000000..4e53474 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/base/BaseDTO$BaseDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/base/BaseDTO.class b/target/classes/dev/lions/user/manager/dto/base/BaseDTO.class new file mode 100644 index 0000000..5c3e19b Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/base/BaseDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleAssignmentDTO$RoleAssignmentDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/role/RoleAssignmentDTO$RoleAssignmentDTOBuilder.class new file mode 100644 index 0000000..6e6b284 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleAssignmentDTO$RoleAssignmentDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleAssignmentDTO.class b/target/classes/dev/lions/user/manager/dto/role/RoleAssignmentDTO.class new file mode 100644 index 0000000..3bfe9e3 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleAssignmentDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilder.class new file mode 100644 index 0000000..9103326 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilderImpl.class b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilderImpl.class new file mode 100644 index 0000000..5126a6e Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilderImpl.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO.class b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO.class new file mode 100644 index 0000000..542058b Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleCompositeDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleDTOBuilder.class new file mode 100644 index 0000000..de31bf0 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleDTOBuilderImpl.class b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleDTOBuilderImpl.class new file mode 100644 index 0000000..860364b Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleDTO$RoleDTOBuilderImpl.class differ diff --git a/target/classes/dev/lions/user/manager/dto/role/RoleDTO.class b/target/classes/dev/lions/user/manager/dto/role/RoleDTO.class new file mode 100644 index 0000000..b0053a3 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/role/RoleDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilder.class new file mode 100644 index 0000000..d7711e4 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilderImpl.class b/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilderImpl.class new file mode 100644 index 0000000..b8c9933 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilderImpl.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO.class b/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO.class new file mode 100644 index 0000000..9bfcb8d Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserDTO$FederatedIdentityDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserDTO$UserDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/user/UserDTO$UserDTOBuilder.class new file mode 100644 index 0000000..7cbef2e Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserDTO$UserDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserDTO$UserDTOBuilderImpl.class b/target/classes/dev/lions/user/manager/dto/user/UserDTO$UserDTOBuilderImpl.class new file mode 100644 index 0000000..6a0b961 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserDTO$UserDTOBuilderImpl.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserDTO.class b/target/classes/dev/lions/user/manager/dto/user/UserDTO.class new file mode 100644 index 0000000..705ec9d Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO$UserSearchCriteriaDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO$UserSearchCriteriaDTOBuilder.class new file mode 100644 index 0000000..16f4f98 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO$UserSearchCriteriaDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO.class b/target/classes/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO.class new file mode 100644 index 0000000..37af0c9 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserSearchCriteriaDTO.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserSearchResultDTO$UserSearchResultDTOBuilder.class b/target/classes/dev/lions/user/manager/dto/user/UserSearchResultDTO$UserSearchResultDTOBuilder.class new file mode 100644 index 0000000..4b71a79 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserSearchResultDTO$UserSearchResultDTOBuilder.class differ diff --git a/target/classes/dev/lions/user/manager/dto/user/UserSearchResultDTO.class b/target/classes/dev/lions/user/manager/dto/user/UserSearchResultDTO.class new file mode 100644 index 0000000..c4af8d8 Binary files /dev/null and b/target/classes/dev/lions/user/manager/dto/user/UserSearchResultDTO.class differ diff --git a/target/classes/dev/lions/user/manager/enums/audit/TypeActionAudit.class b/target/classes/dev/lions/user/manager/enums/audit/TypeActionAudit.class new file mode 100644 index 0000000..fcd8957 Binary files /dev/null and b/target/classes/dev/lions/user/manager/enums/audit/TypeActionAudit.class differ diff --git a/target/classes/dev/lions/user/manager/enums/role/TypeRole.class b/target/classes/dev/lions/user/manager/enums/role/TypeRole.class new file mode 100644 index 0000000..66cdb88 Binary files /dev/null and b/target/classes/dev/lions/user/manager/enums/role/TypeRole.class differ diff --git a/target/classes/dev/lions/user/manager/enums/user/StatutUser.class b/target/classes/dev/lions/user/manager/enums/user/StatutUser.class new file mode 100644 index 0000000..6ccab28 Binary files /dev/null and b/target/classes/dev/lions/user/manager/enums/user/StatutUser.class differ diff --git a/target/classes/dev/lions/user/manager/service/AuditService.class b/target/classes/dev/lions/user/manager/service/AuditService.class new file mode 100644 index 0000000..ab076d7 Binary files /dev/null and b/target/classes/dev/lions/user/manager/service/AuditService.class differ diff --git a/target/classes/dev/lions/user/manager/service/RoleService.class b/target/classes/dev/lions/user/manager/service/RoleService.class new file mode 100644 index 0000000..ba549a2 Binary files /dev/null and b/target/classes/dev/lions/user/manager/service/RoleService.class differ diff --git a/target/classes/dev/lions/user/manager/service/SyncService.class b/target/classes/dev/lions/user/manager/service/SyncService.class new file mode 100644 index 0000000..8e7e3ce Binary files /dev/null and b/target/classes/dev/lions/user/manager/service/SyncService.class differ diff --git a/target/classes/dev/lions/user/manager/service/UserService.class b/target/classes/dev/lions/user/manager/service/UserService.class new file mode 100644 index 0000000..95fec0c Binary files /dev/null and b/target/classes/dev/lions/user/manager/service/UserService.class differ diff --git a/target/classes/dev/lions/user/manager/validation/ValidationConstants.class b/target/classes/dev/lions/user/manager/validation/ValidationConstants.class new file mode 100644 index 0000000..9567cd2 Binary files /dev/null and b/target/classes/dev/lions/user/manager/validation/ValidationConstants.class differ diff --git a/target/lions-user-manager-server-api-1.0.0.jar b/target/lions-user-manager-server-api-1.0.0.jar new file mode 100644 index 0000000..4cf8046 Binary files /dev/null and b/target/lions-user-manager-server-api-1.0.0.jar differ diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..c5e85dd --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +artifactId=lions-user-manager-server-api +groupId=dev.lions.user.manager +version=1.0.0 diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..dabebf0 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,31 @@ +dev\lions\user\manager\dto\role\RoleDTO$RoleDTOBuilder.class +dev\lions\user\manager\dto\audit\AuditLogDTO.class +dev\lions\user\manager\dto\user\UserSearchCriteriaDTO$UserSearchCriteriaDTOBuilder.class +dev\lions\user\manager\dto\audit\AuditLogDTO$AuditLogDTOBuilder.class +dev\lions\user\manager\dto\role\RoleAssignmentDTO.class +dev\lions\user\manager\dto\base\BaseDTO$BaseDTOBuilder.class +dev\lions\user\manager\enums\role\TypeRole.class +dev\lions\user\manager\dto\base\BaseDTO.class +dev\lions\user\manager\dto\user\UserSearchResultDTO.class +dev\lions\user\manager\enums\user\StatutUser.class +dev\lions\user\manager\dto\role\RoleAssignmentDTO$RoleAssignmentDTOBuilder.class +dev\lions\user\manager\dto\role\RoleDTO$RoleDTOBuilderImpl.class +dev\lions\user\manager\service\SyncService.class +dev\lions\user\manager\service\UserService.class +dev\lions\user\manager\service\AuditService.class +dev\lions\user\manager\dto\role\RoleDTO$RoleCompositeDTO.class +dev\lions\user\manager\dto\user\UserDTO$FederatedIdentityDTO.class +dev\lions\user\manager\dto\user\UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilderImpl.class +dev\lions\user\manager\dto\user\UserSearchResultDTO$UserSearchResultDTOBuilder.class +dev\lions\user\manager\dto\role\RoleDTO.class +dev\lions\user\manager\dto\user\UserDTO$FederatedIdentityDTO$FederatedIdentityDTOBuilder.class +dev\lions\user\manager\dto\role\RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilder.class +dev\lions\user\manager\dto\user\UserDTO$UserDTOBuilder.class +dev\lions\user\manager\dto\user\UserDTO$UserDTOBuilderImpl.class +dev\lions\user\manager\dto\user\UserSearchCriteriaDTO.class +dev\lions\user\manager\enums\audit\TypeActionAudit.class +dev\lions\user\manager\dto\role\RoleDTO$RoleCompositeDTO$RoleCompositeDTOBuilderImpl.class +dev\lions\user\manager\dto\user\UserDTO.class +dev\lions\user\manager\validation\ValidationConstants.class +dev\lions\user\manager\service\RoleService.class +dev\lions\user\manager\dto\audit\AuditLogDTO$AuditLogDTOBuilderImpl.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..4078820 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,15 @@ +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\service\RoleService.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\enums\role\TypeRole.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\enums\user\StatutUser.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\user\UserSearchCriteriaDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\audit\AuditLogDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\service\AuditService.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\base\BaseDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\service\SyncService.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\validation\ValidationConstants.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\role\RoleAssignmentDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\user\UserSearchResultDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\enums\audit\TypeActionAudit.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\user\UserDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\dto\role\RoleDTO.java +C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\src\main\java\dev\lions\user\manager\service\UserService.java