diff --git a/src/main/java/sh/libre/scim/core/AbstractScimService.java b/src/main/java/sh/libre/scim/core/AbstractScimService.java index 1d32e32355..637283c043 100644 --- a/src/main/java/sh/libre/scim/core/AbstractScimService.java +++ b/src/main/java/sh/libre/scim/core/AbstractScimService.java @@ -132,7 +132,7 @@ public abstract class AbstractScimService getResourceStream(); - public void importResources(SynchronizationResult syncRes) { + public void importResources(SynchronizationResult syncRes) throws ScimPropagationException { LOGGER.info("Import"); try { for (S resource : scimClient.listResources()) { @@ -180,13 +180,17 @@ public abstract class AbstractScimService implements AutoCloseable { private static final Logger LOGGER = Logger.getLogger(ScimClient.class); @@ -62,10 +63,11 @@ public class ScimClient implements AutoCloseable { return new ScimClient(scimRequestBuilder, scimResourceType); } - public EntityOnRemoteScimId create(KeycloakId id, S scimForCreation) { - if (scimForCreation.getId().isPresent()) { - throw new IllegalArgumentException( - "%s is already created on remote with id %s".formatted(id, scimForCreation.getId().get()) + public EntityOnRemoteScimId create(KeycloakId id, S scimForCreation) throws ScimPropagationException { + Optional scimForCreationId = scimForCreation.getId(); + if (scimForCreationId.isPresent()) { + throw new ScimPropagationException( + "%s is already created on remote with id %s".formatted(id, scimForCreationId.get()) ); } Retry retry = retryRegistry.retry("create-%s".formatted(id.asString())); diff --git a/src/main/java/sh/libre/scim/core/ScimDispatcher.java b/src/main/java/sh/libre/scim/core/ScimDispatcher.java index 62a8bfbda6..54c4843998 100644 --- a/src/main/java/sh/libre/scim/core/ScimDispatcher.java +++ b/src/main/java/sh/libre/scim/core/ScimDispatcher.java @@ -19,6 +19,7 @@ public class ScimDispatcher { private static final Logger logger = Logger.getLogger(ScimDispatcher.class); private final KeycloakSession session; + private final ScimExceptionHandler exceptionHandler; private boolean clientsInitialized = false; private final List userScimServices = new ArrayList<>(); private final List groupScimServices = new ArrayList<>(); @@ -26,6 +27,7 @@ public class ScimDispatcher { public ScimDispatcher(KeycloakSession session) { this.session = session; + this.exceptionHandler = new ScimExceptionHandler(session); } /** @@ -78,7 +80,7 @@ public class ScimDispatcher { operationToDispatch.acceptThrows(userScimService); servicesCorrectlyPropagated.add(userScimService); } catch (ScimPropagationException e) { - logAndRollback(userScimService.getConfiguration(), e); + exceptionHandler.handleException(userScimService.getConfiguration(), e); } }); // TODO we could iterate on servicesCorrectlyPropagated to undo modification @@ -93,7 +95,7 @@ public class ScimDispatcher { operationToDispatch.acceptThrows(groupScimService); servicesCorrectlyPropagated.add(groupScimService); } catch (ScimPropagationException e) { - logAndRollback(groupScimService.getConfiguration(), e); + exceptionHandler.handleException(groupScimService.getConfiguration(), e); } }); // TODO we could iterate on servicesCorrectlyPropagated to undo modification @@ -109,10 +111,10 @@ public class ScimDispatcher { operationToDispatch.acceptThrows(matchingClient.get()); logger.infof("[SCIM] User operation dispatched to SCIM server %s", matchingClient.get().getConfiguration().getId()); } catch (ScimPropagationException e) { - logAndRollback(matchingClient.get().getConfiguration(), e); + exceptionHandler.handleException(matchingClient.get().getConfiguration(), e); } } else { - logger.error("[SCIM] Could not find a Scim Client matching endpoint configuration" + scimServerConfiguration.getId()); + logger.error("[SCIM] Could not find a Scim Client matching User endpoint configuration" + scimServerConfiguration.getId()); } } @@ -126,10 +128,10 @@ public class ScimDispatcher { operationToDispatch.acceptThrows(matchingClient.get()); logger.infof("[SCIM] Group operation dispatched to SCIM server %s", matchingClient.get().getConfiguration().getId()); } catch (ScimPropagationException e) { - logAndRollback(matchingClient.get().getConfiguration(), e); + exceptionHandler.handleException(matchingClient.get().getConfiguration(), e); } } else { - logger.error("[SCIM] Could not find a Scim Client matching endpoint configuration" + scimServerConfiguration.getId()); + logger.error("[SCIM] Could not find a Scim Client matching Group endpoint configuration" + scimServerConfiguration.getId()); } } @@ -144,11 +146,6 @@ public class ScimDispatcher { userScimServices.clear(); } - private void logAndRollback(ScrimProviderConfiguration scimServerConfiguration, ScimPropagationException e) { - logger.error("[SCIM] Error while propagating to SCIM endpoint " + scimServerConfiguration.getId(), e); - // TODO session.getTransactionManager().rollback(); - } - private void initializeClientsIfNeeded() { if (!clientsInitialized) { clientsInitialized = true; diff --git a/src/main/java/sh/libre/scim/core/ScimExceptionHandler.java b/src/main/java/sh/libre/scim/core/ScimExceptionHandler.java new file mode 100644 index 0000000000..44d65ff0e1 --- /dev/null +++ b/src/main/java/sh/libre/scim/core/ScimExceptionHandler.java @@ -0,0 +1,31 @@ +package sh.libre.scim.core; + +import org.jboss.logging.Logger; +import org.keycloak.models.KeycloakSession; + +/** + * In charge of dealing with SCIM exceptions by ignoring, logging or rollback transaction according to : + * - The context in which it occurs (sync, user creation...) + * - The related SCIM endpoint and its configuration + * - The thrown exception itself + */ +public class ScimExceptionHandler { + + private static final Logger logger = Logger.getLogger(ScimDispatcher.class); + private final KeycloakSession session; + + public ScimExceptionHandler(KeycloakSession session) { + this.session = session; + } + + /** + * Handles the given exception by loggin and/or rollback transaction. + * + * @param scimProviderConfiguration the configuration of the endpoint for which the propagation exception occured + * @param e the occuring exception + */ + public void handleException(ScrimProviderConfiguration scimProviderConfiguration, ScimPropagationException e) { + logger.error("[SCIM] Error while propagating to SCIM endpoint " + scimProviderConfiguration.getId(), e); + // TODO session.getTransactionManager().rollback(); + } +} diff --git a/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java b/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java index 06a01db52b..4195e6b618 100644 --- a/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java +++ b/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java @@ -107,7 +107,7 @@ public class ScimEventListenerProvider implements EventListenerProvider { ScimResourceType type = switch (rawResourceType) { case "users" -> ScimResourceType.USER; case "groups" -> ScimResourceType.GROUP; - default -> throw new IllegalArgumentException("Unsuported resource type: " + rawResourceType); + default -> throw new IllegalArgumentException("Unsupported resource type: " + rawResourceType); }; KeycloakId id = new KeycloakId(matcher.group(2)); handleRoleMappingEvent(event, type, id);