Add option to activate full SCIM requests logs

This commit is contained in:
Alex Morel 2024-07-19 10:12:45 +02:00
parent d8cba394b2
commit 97a3e13bc6
3 changed files with 31 additions and 5 deletions

View file

@ -39,16 +39,17 @@ public class ScimEndpointConfigurationStorageProviderFactory
public SynchronizationResult sync(KeycloakSessionFactory sessionFactory, String realmId, public SynchronizationResult sync(KeycloakSessionFactory sessionFactory, String realmId,
UserStorageProviderModel model) { UserStorageProviderModel model) {
// Manually Launch a synchronization between keycloack and the SCIM endpoint described in the given model // Manually Launch a synchronization between keycloack and the SCIM endpoint described in the given model
LOGGER.infof("[SCIM] Sync from ScimStorageProvider - Realm %s - Model %s", realmId, model.getId()); LOGGER.infof("[SCIM] Sync from ScimStorageProvider - Realm %s - Model %s", realmId, model.getName());
SynchronizationResult result = new SynchronizationResult(); SynchronizationResult result = new SynchronizationResult();
KeycloakModelUtils.runJobInTransaction(sessionFactory, session -> { KeycloakModelUtils.runJobInTransaction(sessionFactory, session -> {
RealmModel realm = session.realms().getRealm(realmId); RealmModel realm = session.realms().getRealm(realmId);
session.getContext().setRealm(realm); session.getContext().setRealm(realm);
ScimDispatcher dispatcher = new ScimDispatcher(session); ScimDispatcher dispatcher = new ScimDispatcher(session);
if (BooleanUtils.TRUE.equals(model.get("propagation-user"))) { LOGGER.info("-->" + model.get(ScrimEndPointConfiguration.CONF_KEY_PROPAGATION_USER) + "//" + model.get(ScrimEndPointConfiguration.CONF_KEY_PROPAGATION_GROUP));
if (BooleanUtils.TRUE.equals(model.get(ScrimEndPointConfiguration.CONF_KEY_PROPAGATION_USER))) {
dispatcher.dispatchUserModificationToOne(model, client -> client.sync(result)); dispatcher.dispatchUserModificationToOne(model, client -> client.sync(result));
} }
if (BooleanUtils.TRUE.equals(model.get("propagation-group"))) { if (BooleanUtils.TRUE.equals(model.get(ScrimEndPointConfiguration.CONF_KEY_PROPAGATION_GROUP))) {
dispatcher.dispatchGroupModificationToOne(model, client -> client.sync(result)); dispatcher.dispatchGroupModificationToOne(model, client -> client.sync(result));
} }
dispatcher.close(); dispatcher.close();
@ -139,6 +140,10 @@ public class ScimEndpointConfigurationStorageProviderFactory
.name(ScrimEndPointConfiguration.CONF_KEY_SYNC_REFRESH) .name(ScrimEndPointConfiguration.CONF_KEY_SYNC_REFRESH)
.type(ProviderConfigProperty.BOOLEAN_TYPE) .type(ProviderConfigProperty.BOOLEAN_TYPE)
.label("Enable refresh during sync") .label("Enable refresh during sync")
.name(ScrimEndPointConfiguration.CONF_KEY_LOG_ALL_SCIM_REQUESTS)
.type(ProviderConfigProperty.BOOLEAN_TYPE)
.label("Log SCIM requests and responses")
.helpText("If true, all sent SCIM requests and responses will be logged")
.add() .add()
.build(); .build();
} }

View file

@ -15,6 +15,7 @@ public class ScrimEndPointConfiguration {
public static final String CONF_KEY_SYNC_REFRESH = "sync-refresh"; public static final String CONF_KEY_SYNC_REFRESH = "sync-refresh";
public static final String CONF_KEY_PROPAGATION_USER = "propagation-user"; public static final String CONF_KEY_PROPAGATION_USER = "propagation-user";
public static final String CONF_KEY_PROPAGATION_GROUP = "propagation-group"; public static final String CONF_KEY_PROPAGATION_GROUP = "propagation-group";
public static final String CONF_KEY_LOG_ALL_SCIM_REQUESTS = "log-all-scim-requests";
private final String endPoint; private final String endPoint;
private final String id; private final String id;
@ -24,6 +25,7 @@ public class ScrimEndPointConfiguration {
private final ImportAction importAction; private final ImportAction importAction;
private final boolean pullFromScimSynchronisationActivated; private final boolean pullFromScimSynchronisationActivated;
private final boolean pushToScimSynchronisationActivated; private final boolean pushToScimSynchronisationActivated;
private final boolean logAllScimRequests;
public ScrimEndPointConfiguration(ComponentModel scimProviderConfiguration) { public ScrimEndPointConfiguration(ComponentModel scimProviderConfiguration) {
try { try {
@ -47,6 +49,7 @@ public class ScrimEndPointConfiguration {
importAction = ImportAction.valueOf(scimProviderConfiguration.get(CONF_KEY_SYNC_IMPORT_ACTION)); importAction = ImportAction.valueOf(scimProviderConfiguration.get(CONF_KEY_SYNC_IMPORT_ACTION));
pullFromScimSynchronisationActivated = scimProviderConfiguration.get(CONF_KEY_SYNC_IMPORT, false); pullFromScimSynchronisationActivated = scimProviderConfiguration.get(CONF_KEY_SYNC_IMPORT, false);
pushToScimSynchronisationActivated = scimProviderConfiguration.get(CONF_KEY_SYNC_REFRESH, false); pushToScimSynchronisationActivated = scimProviderConfiguration.get(CONF_KEY_SYNC_REFRESH, false);
logAllScimRequests = scimProviderConfiguration.get(CONF_KEY_LOG_ALL_SCIM_REQUESTS, false);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IllegalArgumentException("authMode '" + scimProviderConfiguration.get(CONF_KEY_AUTH_MODE) + "' is not supported"); throw new IllegalArgumentException("authMode '" + scimProviderConfiguration.get(CONF_KEY_AUTH_MODE) + "' is not supported");
} }
@ -84,6 +87,10 @@ public class ScrimEndPointConfiguration {
return endPoint; return endPoint;
} }
public boolean isLogAllScimRequests() {
return logAllScimRequests;
}
public enum AuthMode { public enum AuthMode {
BEARER, BASIC_AUTH, NONE BEARER, BASIC_AUTH, NONE
} }

View file

@ -28,8 +28,9 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
private final ScimRequestBuilder scimRequestBuilder; private final ScimRequestBuilder scimRequestBuilder;
private final ScimResourceType scimResourceType; private final ScimResourceType scimResourceType;
private final boolean logAllRequests;
private ScimClient(ScimRequestBuilder scimRequestBuilder, ScimResourceType scimResourceType) { private ScimClient(ScimRequestBuilder scimRequestBuilder, ScimResourceType scimResourceType, boolean detailedLogs) {
this.scimRequestBuilder = scimRequestBuilder; this.scimRequestBuilder = scimRequestBuilder;
this.scimResourceType = scimResourceType; this.scimResourceType = scimResourceType;
RetryConfig retryConfig = RetryConfig.custom() RetryConfig retryConfig = RetryConfig.custom()
@ -38,6 +39,7 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
.retryExceptions(ProcessingException.class) .retryExceptions(ProcessingException.class)
.build(); .build();
retryRegistry = RetryRegistry.of(retryConfig); retryRegistry = RetryRegistry.of(retryConfig);
this.logAllRequests = detailedLogs;
} }
public static ScimClient open(ScrimEndPointConfiguration scimProviderConfiguration, ScimResourceType scimResourceType) { public static ScimClient open(ScrimEndPointConfiguration scimProviderConfiguration, ScimResourceType scimResourceType) {
@ -56,7 +58,7 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
scimApplicationBaseUrl, scimApplicationBaseUrl,
scimClientConfig scimClientConfig
); );
return new ScimClient(scimRequestBuilder, scimResourceType); return new ScimClient(scimRequestBuilder, scimResourceType, scimProviderConfiguration.isLogAllScimRequests());
} }
public EntityOnRemoteScimId create(KeycloakId id, S scimForCreation) throws InvalidResponseFromScimEndpointException { public EntityOnRemoteScimId create(KeycloakId id, S scimForCreation) throws InvalidResponseFromScimEndpointException {
@ -68,6 +70,9 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
} }
try { try {
Retry retry = retryRegistry.retry("create-%s".formatted(id.asString())); Retry retry = retryRegistry.retry("create-%s".formatted(id.asString()));
if (logAllRequests) {
LOGGER.warn("[SCIM] Sending " + scimForCreation.toPrettyString() + "\n to " + getScimEndpoint());
}
ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder
.create(getResourceClass(), getScimEndpoint()) .create(getResourceClass(), getScimEndpoint())
.setResource(scimForCreation) .setResource(scimForCreation)
@ -86,6 +91,9 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
} }
private void checkResponseIsSuccess(ServerResponse<S> response) throws InvalidResponseFromScimEndpointException { private void checkResponseIsSuccess(ServerResponse<S> response) throws InvalidResponseFromScimEndpointException {
if (logAllRequests) {
LOGGER.warn("[SCIM] Server response " + response.getHttpStatus() + "\n" + response.getResponseBody());
}
if (!response.isSuccess()) { if (!response.isSuccess()) {
throw new InvalidResponseFromScimEndpointException(response, "Server answered with status " + response.getResponseBody() + ": " + response.getResponseBody()); throw new InvalidResponseFromScimEndpointException(response, "Server answered with status " + response.getResponseBody() + ": " + response.getResponseBody());
} }
@ -102,6 +110,9 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
public void update(EntityOnRemoteScimId externalId, S scimForReplace) throws InvalidResponseFromScimEndpointException { public void update(EntityOnRemoteScimId externalId, S scimForReplace) throws InvalidResponseFromScimEndpointException {
Retry retry = retryRegistry.retry("replace-%s".formatted(externalId.asString())); Retry retry = retryRegistry.retry("replace-%s".formatted(externalId.asString()));
try { try {
if (logAllRequests) {
LOGGER.warn("[SCIM] Sending Update " + scimForReplace.toPrettyString() + "\n to " + getScimEndpoint());
}
ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder
.update(getResourceClass(), getScimEndpoint(), externalId.asString()) .update(getResourceClass(), getScimEndpoint(), externalId.asString())
.setResource(scimForReplace) .setResource(scimForReplace)
@ -116,6 +127,9 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
public void delete(EntityOnRemoteScimId externalId) throws InvalidResponseFromScimEndpointException { public void delete(EntityOnRemoteScimId externalId) throws InvalidResponseFromScimEndpointException {
Retry retry = retryRegistry.retry("delete-%s".formatted(externalId.asString())); Retry retry = retryRegistry.retry("delete-%s".formatted(externalId.asString()));
if (logAllRequests) {
LOGGER.warn("[SCIM] Sending DELETE to " + getScimEndpoint());
}
try { try {
ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder
.delete(getResourceClass(), getScimEndpoint(), externalId.asString()) .delete(getResourceClass(), getScimEndpoint(), externalId.asString())