chore(quarkus-327): bump to Quarkus 3.27.3 LTS, make pom autonomous, fix UserServiceImpl tests (search → searchByUsername), rename deprecated config keys
Some checks failed
CI/CD Pipeline / pipeline (push) Failing after 1m57s

This commit is contained in:
2026-04-23 14:47:26 +00:00
parent 16240fedc1
commit 41d87451c9
84 changed files with 12016 additions and 11970 deletions

View File

@@ -1,22 +1,22 @@
package dev.lions.user.manager.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
/**
* Configure Jackson globally to ignore unknown JSON properties.
* This is required for forward compatibility with newer Keycloak versions (e.g. cpuInfo field).
*/
@Singleton
@Slf4j
public class JacksonConfig implements ObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
log.info("### LIONS: Applying Jackson configuration for Keycloak compatibility ###");
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
package dev.lions.user.manager.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
/**
* Configure Jackson globally to ignore unknown JSON properties.
* This is required for forward compatibility with newer Keycloak versions (e.g. cpuInfo field).
*/
@Singleton
@Slf4j
public class JacksonConfig implements ObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
log.info("### LIONS: Applying Jackson configuration for Keycloak compatibility ###");
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}

View File

@@ -1,33 +1,33 @@
package dev.lions.user.manager.config;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
/**
* Customizer pour Jackson afin d'ignorer les propriétés inconnues dans les
* représentations Keycloak.
* Cela évite les erreurs de désérialisation (comme bruteForceStrategy) lorsque
* le serveur Keycloak
* est plus récent que les bibliothèques clients.
*/
@Singleton
public class KeycloakJacksonCustomizer implements ObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
// En plus de la configuration globale, on force les Mix-ins pour les classes
// Keycloak critiques
objectMapper.addMixIn(RealmRepresentation.class, IgnoreUnknownMixin.class);
objectMapper.addMixIn(UserRepresentation.class, IgnoreUnknownMixin.class);
objectMapper.addMixIn(RoleRepresentation.class, IgnoreUnknownMixin.class);
}
@JsonIgnoreProperties(ignoreUnknown = true)
abstract static class IgnoreUnknownMixin {
}
}
package dev.lions.user.manager.config;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
/**
* Customizer pour Jackson afin d'ignorer les propriétés inconnues dans les
* représentations Keycloak.
* Cela évite les erreurs de désérialisation (comme bruteForceStrategy) lorsque
* le serveur Keycloak
* est plus récent que les bibliothèques clients.
*/
@Singleton
public class KeycloakJacksonCustomizer implements ObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
// En plus de la configuration globale, on force les Mix-ins pour les classes
// Keycloak critiques
objectMapper.addMixIn(RealmRepresentation.class, IgnoreUnknownMixin.class);
objectMapper.addMixIn(UserRepresentation.class, IgnoreUnknownMixin.class);
objectMapper.addMixIn(RoleRepresentation.class, IgnoreUnknownMixin.class);
}
@JsonIgnoreProperties(ignoreUnknown = true)
abstract static class IgnoreUnknownMixin {
}
}

View File

@@ -1,281 +1,281 @@
package dev.lions.user.manager.config;
import io.quarkus.arc.profile.IfBuildProfile;
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
@IfBuildProfile("dev")
@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());
}
}
package dev.lions.user.manager.config;
import io.quarkus.arc.profile.IfBuildProfile;
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
@IfBuildProfile("dev")
@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());
}
}