Migration complète vers PrimeFaces Freya - Corrections des incompatibilités et intégration de primefaces-freya-extension
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
package dev.lions.user.manager.config;
|
||||
|
||||
import io.quarkus.runtime.StartupEvent;
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.KeycloakBuilder;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Configuration automatique de Keycloak pour l'utilisateur de test
|
||||
* S'exécute au démarrage de l'application en mode dev
|
||||
*/
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class KeycloakTestUserConfig {
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "quarkus.profile", defaultValue = "prod")
|
||||
String profile;
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "lions.keycloak.server-url")
|
||||
String keycloakServerUrl;
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "lions.keycloak.admin-realm", defaultValue = "master")
|
||||
String adminRealm;
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "lions.keycloak.admin-username", defaultValue = "admin")
|
||||
String adminUsername;
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "lions.keycloak.admin-password", defaultValue = "admin")
|
||||
String adminPassword;
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "lions.keycloak.authorized-realms")
|
||||
String authorizedRealms;
|
||||
|
||||
private static final String TEST_REALM = "lions-user-manager";
|
||||
private static final String TEST_USER = "test-user";
|
||||
private static final String TEST_PASSWORD = "test123";
|
||||
private static final String TEST_EMAIL = "test@lions.dev";
|
||||
private static final String CLIENT_ID = "lions-user-manager-client";
|
||||
|
||||
private static final List<String> REQUIRED_ROLES = Arrays.asList(
|
||||
"admin", "user_manager", "user_viewer",
|
||||
"role_manager", "role_viewer", "auditor", "sync_manager"
|
||||
);
|
||||
|
||||
void onStart(@Observes StartupEvent ev) {
|
||||
// DÉSACTIVÉ: Configuration manuelle via script create-roles-and-assign.sh
|
||||
// Cette configuration automatique cause des erreurs de compatibilité Keycloak
|
||||
// (bruteForceStrategy, cpuInfo non reconnus par la version Keycloak client)
|
||||
log.info("Configuration automatique de Keycloak DÉSACTIVÉE");
|
||||
log.info("Utiliser le script create-roles-and-assign.sh pour configurer Keycloak manuellement");
|
||||
return;
|
||||
|
||||
/* ANCIEN CODE DÉSACTIVÉ
|
||||
// Ne s'exécuter qu'en mode dev
|
||||
if (!"dev".equals(profile) && !"development".equals(profile)) {
|
||||
log.debug("Mode non-dev détecté ({}), configuration Keycloak ignorée", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("Configuration automatique de Keycloak pour l'utilisateur de test...");
|
||||
|
||||
Keycloak adminClient = null;
|
||||
try {
|
||||
// Connexion en tant qu'admin
|
||||
adminClient = KeycloakBuilder.builder()
|
||||
.serverUrl(keycloakServerUrl)
|
||||
.realm(adminRealm)
|
||||
.username(adminUsername)
|
||||
.password(adminPassword)
|
||||
.clientId("admin-cli")
|
||||
.build();
|
||||
|
||||
// 1. Vérifier/Créer le realm
|
||||
ensureRealmExists(adminClient);
|
||||
|
||||
// 2. Créer les rôles
|
||||
ensureRolesExist(adminClient);
|
||||
|
||||
// 3. Créer l'utilisateur de test
|
||||
String userId = ensureTestUserExists(adminClient);
|
||||
|
||||
// 4. Assigner les rôles
|
||||
assignRolesToUser(adminClient, userId);
|
||||
|
||||
// 5. Vérifier/Créer le client et le mapper
|
||||
ensureClientAndMapper(adminClient);
|
||||
|
||||
log.info("✓ Configuration Keycloak terminée avec succès");
|
||||
log.info(" Utilisateur de test: {} / {}", TEST_USER, TEST_PASSWORD);
|
||||
log.info(" Rôles assignés: {}", String.join(", ", REQUIRED_ROLES));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Erreur lors de la configuration Keycloak: {}", e.getMessage(), e);
|
||||
} finally {
|
||||
if (adminClient != null) {
|
||||
adminClient.close();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private void ensureRealmExists(Keycloak adminClient) {
|
||||
try {
|
||||
adminClient.realms().realm(TEST_REALM).toRepresentation();
|
||||
log.debug("Realm '{}' existe déjà", TEST_REALM);
|
||||
} catch (jakarta.ws.rs.NotFoundException e) {
|
||||
log.info("Création du realm '{}'...", TEST_REALM);
|
||||
RealmRepresentation realm = new RealmRepresentation();
|
||||
realm.setRealm(TEST_REALM);
|
||||
realm.setEnabled(true);
|
||||
adminClient.realms().create(realm);
|
||||
log.info("✓ Realm '{}' créé", TEST_REALM);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureRolesExist(Keycloak adminClient) {
|
||||
var rolesResource = adminClient.realms().realm(TEST_REALM).roles();
|
||||
|
||||
for (String roleName : REQUIRED_ROLES) {
|
||||
try {
|
||||
rolesResource.get(roleName).toRepresentation();
|
||||
log.debug("Rôle '{}' existe déjà", roleName);
|
||||
} catch (jakarta.ws.rs.NotFoundException e) {
|
||||
log.info("Création du rôle '{}'...", roleName);
|
||||
RoleRepresentation role = new RoleRepresentation();
|
||||
role.setName(roleName);
|
||||
role.setDescription("Rôle " + roleName + " pour lions-user-manager");
|
||||
rolesResource.create(role);
|
||||
log.info("✓ Rôle '{}' créé", roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String ensureTestUserExists(Keycloak adminClient) {
|
||||
var usersResource = adminClient.realms().realm(TEST_REALM).users();
|
||||
|
||||
// Chercher l'utilisateur
|
||||
List<UserRepresentation> users = usersResource.search(TEST_USER, true);
|
||||
|
||||
String userId;
|
||||
if (users != null && !users.isEmpty()) {
|
||||
userId = users.get(0).getId();
|
||||
log.debug("Utilisateur '{}' existe déjà (ID: {})", TEST_USER, userId);
|
||||
} else {
|
||||
log.info("Création de l'utilisateur '{}'...", TEST_USER);
|
||||
UserRepresentation user = new UserRepresentation();
|
||||
user.setUsername(TEST_USER);
|
||||
user.setEmail(TEST_EMAIL);
|
||||
user.setFirstName("Test");
|
||||
user.setLastName("User");
|
||||
user.setEnabled(true);
|
||||
user.setEmailVerified(true);
|
||||
|
||||
jakarta.ws.rs.core.Response response = usersResource.create(user);
|
||||
userId = getCreatedId(response);
|
||||
|
||||
// Définir le mot de passe
|
||||
CredentialRepresentation credential = new CredentialRepresentation();
|
||||
credential.setType(CredentialRepresentation.PASSWORD);
|
||||
credential.setValue(TEST_PASSWORD);
|
||||
credential.setTemporary(false);
|
||||
usersResource.get(userId).resetPassword(credential);
|
||||
|
||||
log.info("✓ Utilisateur '{}' créé (ID: {})", TEST_USER, userId);
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
private void assignRolesToUser(Keycloak adminClient, String userId) {
|
||||
var usersResource = adminClient.realms().realm(TEST_REALM).users();
|
||||
var rolesResource = adminClient.realms().realm(TEST_REALM).roles();
|
||||
|
||||
List<RoleRepresentation> rolesToAssign = new ArrayList<>();
|
||||
for (String roleName : REQUIRED_ROLES) {
|
||||
RoleRepresentation role = rolesResource.get(roleName).toRepresentation();
|
||||
rolesToAssign.add(role);
|
||||
}
|
||||
|
||||
usersResource.get(userId).roles().realmLevel().add(rolesToAssign);
|
||||
log.info("✓ {} rôles assignés à l'utilisateur", rolesToAssign.size());
|
||||
}
|
||||
|
||||
private void ensureClientAndMapper(Keycloak adminClient) {
|
||||
try {
|
||||
var clientsResource = adminClient.realms().realm(TEST_REALM).clients();
|
||||
var clients = clientsResource.findByClientId(CLIENT_ID);
|
||||
|
||||
String clientId;
|
||||
if (clients == null || clients.isEmpty()) {
|
||||
log.info("Création du client '{}'...", CLIENT_ID);
|
||||
org.keycloak.representations.idm.ClientRepresentation client = new org.keycloak.representations.idm.ClientRepresentation();
|
||||
client.setClientId(CLIENT_ID);
|
||||
client.setName(CLIENT_ID);
|
||||
client.setDescription("Client OIDC pour lions-user-manager");
|
||||
client.setEnabled(true);
|
||||
client.setPublicClient(false);
|
||||
client.setStandardFlowEnabled(true);
|
||||
client.setDirectAccessGrantsEnabled(true);
|
||||
client.setFullScopeAllowed(true); // IMPORTANT: Permet d'inclure tous les rôles dans le token
|
||||
client.setRedirectUris(java.util.Arrays.asList(
|
||||
"http://localhost:8080/*",
|
||||
"http://localhost:8080/auth/callback"
|
||||
));
|
||||
client.setWebOrigins(java.util.Arrays.asList("http://localhost:8080"));
|
||||
client.setSecret("NTuaQpk5E6qiMqAWTFrCOcIkOABzZzKO");
|
||||
|
||||
jakarta.ws.rs.core.Response response = clientsResource.create(client);
|
||||
clientId = getCreatedId(response);
|
||||
log.info("✓ Client '{}' créé (ID: {})", CLIENT_ID, clientId);
|
||||
} else {
|
||||
clientId = clients.get(0).getId();
|
||||
log.debug("Client '{}' existe déjà (ID: {})", CLIENT_ID, clientId);
|
||||
}
|
||||
|
||||
// Ajouter le scope "roles" par défaut au client
|
||||
try {
|
||||
var clientScopesResource = adminClient.realms().realm(TEST_REALM).clientScopes();
|
||||
var defaultClientScopes = clientScopesResource.findAll();
|
||||
var rolesScope = defaultClientScopes.stream()
|
||||
.filter(s -> "roles".equals(s.getName()))
|
||||
.findFirst();
|
||||
|
||||
if (rolesScope.isPresent()) {
|
||||
var clientResource = clientsResource.get(clientId);
|
||||
var defaultScopes = clientResource.getDefaultClientScopes();
|
||||
boolean hasRolesScope = defaultScopes.stream()
|
||||
.anyMatch(s -> "roles".equals(s.getName()));
|
||||
|
||||
if (!hasRolesScope) {
|
||||
log.info("Ajout du scope 'roles' au client...");
|
||||
clientResource.addDefaultClientScope(rolesScope.get().getId());
|
||||
log.info("✓ Scope 'roles' ajouté au client");
|
||||
} else {
|
||||
log.debug("Scope 'roles' déjà présent sur le client");
|
||||
}
|
||||
} else {
|
||||
log.warn("Scope 'roles' non trouvé dans les scopes par défaut du realm");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Erreur lors de l'ajout du scope 'roles': {}", e.getMessage());
|
||||
}
|
||||
|
||||
// Le scope "roles" de Keycloak crée automatiquement realm_access.roles
|
||||
// Pas besoin de mapper personnalisé si on utilise realm_access.roles
|
||||
// Le mapper personnalisé peut créer des conflits (comme dans unionflow)
|
||||
log.debug("Le scope 'roles' est utilisé pour créer realm_access.roles automatiquement");
|
||||
} catch (Exception e) {
|
||||
log.warn("Erreur lors de la vérification/création du client: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getCreatedId(jakarta.ws.rs.core.Response response) {
|
||||
jakarta.ws.rs.core.Response.StatusType statusInfo = response.getStatusInfo();
|
||||
if (statusInfo.equals(jakarta.ws.rs.core.Response.Status.CREATED)) {
|
||||
String location = response.getLocation().getPath();
|
||||
return location.substring(location.lastIndexOf('/') + 1);
|
||||
}
|
||||
throw new RuntimeException("Erreur lors de la création: " + statusInfo.getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user