Use enum interfaces for RollbackStrategy and SkipOrStopStrategy
This commit is contained in:
parent
620c9e84bb
commit
387abc30f8
6 changed files with 51 additions and 92 deletions
|
@ -5,8 +5,8 @@ import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import sh.libre.scim.core.exceptions.ScimExceptionHandler;
|
import sh.libre.scim.core.exceptions.ScimExceptionHandler;
|
||||||
import sh.libre.scim.core.exceptions.ScimPropagationException;
|
import sh.libre.scim.core.exceptions.ScimPropagationException;
|
||||||
|
import sh.libre.scim.core.exceptions.SkipOrStopApproach;
|
||||||
import sh.libre.scim.core.exceptions.SkipOrStopStrategy;
|
import sh.libre.scim.core.exceptions.SkipOrStopStrategy;
|
||||||
import sh.libre.scim.core.exceptions.SkipOrStopStrategyFactory;
|
|
||||||
import sh.libre.scim.storage.ScimEndpointConfigurationStorageProviderFactory;
|
import sh.libre.scim.storage.ScimEndpointConfigurationStorageProviderFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -34,9 +34,7 @@ public class ScimDispatcher {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.exceptionHandler = new ScimExceptionHandler(session);
|
this.exceptionHandler = new ScimExceptionHandler(session);
|
||||||
// By default, use a permissive Skip or Stop strategy
|
// By default, use a permissive Skip or Stop strategy
|
||||||
this.skipOrStopStrategy = SkipOrStopStrategyFactory.create(
|
this.skipOrStopStrategy = SkipOrStopApproach.ALWAYS_SKIP_AND_CONTINUE;
|
||||||
SkipOrStopStrategyFactory.SkipOrStopApproach.ALWAYS_SKIP_AND_CONTINUE
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package sh.libre.scim.core.exceptions;
|
||||||
|
|
||||||
|
import sh.libre.scim.core.ScrimEndPointConfiguration;
|
||||||
|
|
||||||
|
|
||||||
|
public enum RollbackApproach implements RollbackStrategy {
|
||||||
|
ALWAYS_ROLLBACK {
|
||||||
|
@Override
|
||||||
|
public boolean shouldRollback(ScrimEndPointConfiguration configuration, ScimPropagationException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NEVER_ROLLBACK {
|
||||||
|
@Override
|
||||||
|
public boolean shouldRollback(ScrimEndPointConfiguration configuration, ScimPropagationException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CRITICAL_ONLY_ROLLBACK {
|
||||||
|
@Override
|
||||||
|
public boolean shouldRollback(ScrimEndPointConfiguration configuration, ScimPropagationException e) {
|
||||||
|
if (e instanceof InconsistentScimMappingException) {
|
||||||
|
// Occurs when mapping between a SCIM resource and a keycloak user failed (missing, ambiguous..)
|
||||||
|
// Log can be sufficient here, no rollback required
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e instanceof UnexpectedScimDataException) {
|
||||||
|
// Occurs when a SCIM endpoint sends invalid date (e.g. group with empty name, user without ids...)
|
||||||
|
// No rollback required : we cannot recover. This needs to be fixed in the SCIM endpoint data
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e instanceof InvalidResponseFromScimEndpointException invalidResponseFromScimEndpointException) {
|
||||||
|
return shouldRollbackBecauseOfResponse(invalidResponseFromScimEndpointException);
|
||||||
|
}
|
||||||
|
// Should not occur
|
||||||
|
throw new IllegalStateException("Unkown ScimPropagationException", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldRollbackBecauseOfResponse(InvalidResponseFromScimEndpointException e) {
|
||||||
|
int httpStatus = e.getResponse().getHttpStatus();
|
||||||
|
return httpStatus == 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
package sh.libre.scim.core.exceptions;
|
|
||||||
|
|
||||||
import sh.libre.scim.core.ScrimEndPointConfiguration;
|
|
||||||
|
|
||||||
public class RollbackOnlyForCriticalErrorsStrategy implements RollbackStrategy {
|
|
||||||
|
|
||||||
private boolean shouldRollback(InvalidResponseFromScimEndpointException e) {
|
|
||||||
int httpStatus = e.getResponse().getHttpStatus();
|
|
||||||
return httpStatus == 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldRollback(ScrimEndPointConfiguration configuration, ScimPropagationException e) {
|
|
||||||
if (e instanceof InvalidResponseFromScimEndpointException invalidResponseFromScimEndpointException) {
|
|
||||||
return shouldRollback(invalidResponseFromScimEndpointException);
|
|
||||||
}
|
|
||||||
if (e instanceof InconsistentScimMappingException) {
|
|
||||||
// Occurs when mapping between a SCIM resource and a keycloak user failed (missing, ambiguous..)
|
|
||||||
// Log can be sufficient here, no rollback required
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (e instanceof UnexpectedScimDataException) {
|
|
||||||
// Occurs when a SCIM endpoint sends invalid date (e.g. group with empty name, user without ids...)
|
|
||||||
// No rollback required : we cannot recover. This needs to be fixed in the SCIM endpoint data
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Should not occur
|
|
||||||
throw new IllegalStateException("Unkown ScimPropagationException", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package sh.libre.scim.core.exceptions;
|
|
||||||
|
|
||||||
import sh.libre.scim.core.ScrimEndPointConfiguration;
|
|
||||||
|
|
||||||
public class RollbackStrategyFactory {
|
|
||||||
|
|
||||||
public static RollbackStrategy create(RollbackApproach approach) {
|
|
||||||
// We could imagine more fine-grained rollback strategies (e.g. based on each Scim endpoint configuration)
|
|
||||||
return switch (approach) {
|
|
||||||
case ALWAYS_ROLLBACK -> new AlwaysRollbackStrategy();
|
|
||||||
case NEVER_ROLLBACK -> new NeverRollbackStrategy();
|
|
||||||
case CRITICAL_ONLY_ROLLBACK -> new RollbackOnlyForCriticalErrorsStrategy();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum RollbackApproach {
|
|
||||||
ALWAYS_ROLLBACK, NEVER_ROLLBACK, CRITICAL_ONLY_ROLLBACK
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final class AlwaysRollbackStrategy implements RollbackStrategy {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldRollback(ScrimEndPointConfiguration configuration, ScimPropagationException e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class NeverRollbackStrategy implements RollbackStrategy {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldRollback(ScrimEndPointConfiguration configuration, ScimPropagationException e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,7 +17,7 @@ public class ScimExceptionHandler {
|
||||||
private final RollbackStrategy rollbackStrategy;
|
private final RollbackStrategy rollbackStrategy;
|
||||||
|
|
||||||
public ScimExceptionHandler(KeycloakSession session) {
|
public ScimExceptionHandler(KeycloakSession session) {
|
||||||
this(session, RollbackStrategyFactory.create(RollbackStrategyFactory.RollbackApproach.CRITICAL_ONLY_ROLLBACK));
|
this(session, RollbackApproach.CRITICAL_ONLY_ROLLBACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScimExceptionHandler(KeycloakSession session, RollbackStrategy rollbackStrategy) {
|
public ScimExceptionHandler(KeycloakSession session, RollbackStrategy rollbackStrategy) {
|
||||||
|
|
|
@ -2,22 +2,9 @@ package sh.libre.scim.core.exceptions;
|
||||||
|
|
||||||
import sh.libre.scim.core.ScrimEndPointConfiguration;
|
import sh.libre.scim.core.ScrimEndPointConfiguration;
|
||||||
|
|
||||||
public class SkipOrStopStrategyFactory {
|
|
||||||
|
|
||||||
public static SkipOrStopStrategy create(SkipOrStopApproach approach) {
|
|
||||||
// We could imagine more fine-grained strategies (e.g. based on each Scim endpoint configuration)
|
|
||||||
return switch (approach) {
|
|
||||||
case ALWAYS_STOP -> new AlwaysStopStrategy();
|
|
||||||
case ALWAYS_SKIP_AND_CONTINUE -> new AlwaysSkipAndContinueStrategy();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SkipOrStopApproach {
|
|
||||||
ALWAYS_SKIP_AND_CONTINUE, ALWAYS_STOP
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class AlwaysStopStrategy implements SkipOrStopStrategy {
|
|
||||||
|
|
||||||
|
public enum SkipOrStopApproach implements SkipOrStopStrategy {
|
||||||
|
ALWAYS_SKIP_AND_CONTINUE {
|
||||||
@Override
|
@Override
|
||||||
public boolean allowPartialSynchronizationWhenPushingToScim(ScrimEndPointConfiguration configuration) {
|
public boolean allowPartialSynchronizationWhenPushingToScim(ScrimEndPointConfiguration configuration) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -42,10 +29,8 @@ public class SkipOrStopStrategyFactory {
|
||||||
public boolean skipInvalidDataFromScimEndpoint(ScrimEndPointConfiguration configuration) {
|
public boolean skipInvalidDataFromScimEndpoint(ScrimEndPointConfiguration configuration) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
ALWAYS_STOP {
|
||||||
private static final class AlwaysSkipAndContinueStrategy implements SkipOrStopStrategy {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean allowPartialSynchronizationWhenPushingToScim(ScrimEndPointConfiguration configuration) {
|
public boolean allowPartialSynchronizationWhenPushingToScim(ScrimEndPointConfiguration configuration) {
|
||||||
return true;
|
return true;
|
Loading…
Reference in a new issue