Avoid recreating ScimClients at every change propagation : code refactoring
This commit is contained in:
parent
f00130d37a
commit
633291d401
4 changed files with 88 additions and 42 deletions
|
@ -30,6 +30,11 @@ public class GroupScimClient implements ScimClientInterface<GroupModel> {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScrimProviderConfiguration getConfiguration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -39,4 +39,9 @@ public interface ScimClientInterface<M extends RoleMapperModel> extends AutoClos
|
|||
* @param result the synchronization result to update for indicating triggered operations (e.g. user deletions)
|
||||
*/
|
||||
void sync(SynchronizationResult result);
|
||||
|
||||
/**
|
||||
* @return the {@link ScrimProviderConfiguration} corresponding to this client.
|
||||
*/
|
||||
ScrimProviderConfiguration getConfiguration();
|
||||
}
|
||||
|
|
|
@ -5,66 +5,97 @@ import org.keycloak.component.ComponentModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import sh.libre.scim.storage.ScimStorageProviderFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* In charge of sending SCIM Request to all registered Scim endpoints.
|
||||
*/
|
||||
public class ScimDispatcher {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ScimDispatcher.class);
|
||||
private static final Logger logger = Logger.getLogger(ScimDispatcher.class);
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final List<UserScimClient> userScimClients = new ArrayList<>();
|
||||
private final List<GroupScimClient> groupScimClients = new ArrayList<>();
|
||||
|
||||
public ScimDispatcher(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void dispatchUserModificationToAll(Consumer<UserScimClient> operationToDispatch) {
|
||||
getAllSCIMServer(Scope.USER).forEach(scimServerConfiguration -> dispatchUserModificationToOne(scimServerConfiguration, operationToDispatch));
|
||||
}
|
||||
|
||||
public void dispatchUserModificationToOne(ComponentModel scimServerConfiguration, Consumer<UserScimClient> operationToDispatch) {
|
||||
LOGGER.infof("%s %s %s %s", scimServerConfiguration.getId(), scimServerConfiguration.getName(), scimServerConfiguration.getProviderId(), scimServerConfiguration.getProviderType());
|
||||
try (UserScimClient client = UserScimClient.newUserScimClient(scimServerConfiguration, session)) {
|
||||
operationToDispatch.accept(client);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchGroupModificationToAll(Consumer<GroupScimClient> operationToDispatch) {
|
||||
getAllSCIMServer(Scope.GROUP).forEach(scimServerConfiguration -> dispatchGroupModificationToOne(scimServerConfiguration, operationToDispatch));
|
||||
}
|
||||
|
||||
public void dispatchGroupModificationToOne(ComponentModel scimServerConfiguration, Consumer<GroupScimClient> operationToDispatch) {
|
||||
LOGGER.infof("%s %s %s %s", scimServerConfiguration.getId(), scimServerConfiguration.getName(), scimServerConfiguration.getProviderId(), scimServerConfiguration.getProviderType());
|
||||
try (GroupScimClient client = GroupScimClient.newGroupScimClient(scimServerConfiguration, session)) {
|
||||
operationToDispatch.accept(client);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e);
|
||||
}
|
||||
refreshActiveScimEndpoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scope The {@link Scope} to consider (User or Group)
|
||||
* @return all enabled registered Scim endpoints with propagation enabled for the given scope
|
||||
* Lists all active ScimStorageProviderFactory and create new ScimClients for each of them
|
||||
*/
|
||||
private Stream<ComponentModel> getAllSCIMServer(Scope scope) {
|
||||
// TODO : we could initiative this list once and invalidate it when configuration changes
|
||||
|
||||
String propagationConfKey = switch (scope) {
|
||||
case GROUP -> ScrimProviderConfiguration.CONF_KEY_PROPAGATION_GROUP;
|
||||
case USER -> ScrimProviderConfiguration.CONF_KEY_PROPAGATION_USER;
|
||||
};
|
||||
return session.getContext().getRealm().getComponentsStream()
|
||||
.filter(m -> ScimStorageProviderFactory.ID.equals(m.getProviderId())
|
||||
&& m.get("enabled", true)
|
||||
&& m.get(propagationConfKey, false));
|
||||
public void refreshActiveScimEndpoints() {
|
||||
try {
|
||||
// Step 1: close existing clients
|
||||
for (GroupScimClient c : groupScimClients) {
|
||||
c.close();
|
||||
}
|
||||
for (UserScimClient c : userScimClients) {
|
||||
c.close();
|
||||
}
|
||||
|
||||
public enum Scope {
|
||||
USER, GROUP
|
||||
// Step 2: Get All SCIM endpoints defined in Admin Console (enabled ScimStorageProviderFactory)
|
||||
session.getContext().getRealm().getComponentsStream()
|
||||
.filter(m -> ScimStorageProviderFactory.ID.equals(m.getProviderId())
|
||||
&& m.get("enabled", true))
|
||||
.forEach(scimEndpoint -> {
|
||||
// Step 3 : create scim clients for each endpoint
|
||||
if (scimEndpoint.get(ScrimProviderConfiguration.CONF_KEY_PROPAGATION_GROUP, false)) {
|
||||
GroupScimClient groupScimClient = GroupScimClient.newGroupScimClient(scimEndpoint, session);
|
||||
groupScimClients.add(groupScimClient);
|
||||
}
|
||||
if (scimEndpoint.get(ScrimProviderConfiguration.CONF_KEY_PROPAGATION_USER, false)) {
|
||||
UserScimClient userScimClient = UserScimClient.newUserScimClient(scimEndpoint, session);
|
||||
userScimClients.add(userScimClient);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error("[SCIM] Error while refreshing scim clients ", e);
|
||||
// TODO : how to handle exception here ?
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchUserModificationToAll(Consumer<UserScimClient> operationToDispatch) {
|
||||
// TODO should not be required to launch a refresh here : we should refresh clients only if an endpoint configuration changes
|
||||
refreshActiveScimEndpoints();
|
||||
userScimClients.forEach(operationToDispatch);
|
||||
}
|
||||
|
||||
public void dispatchGroupModificationToAll(Consumer<GroupScimClient> operationToDispatch) {
|
||||
// TODO should not be required to launch a refresh here : we should refresh clients only if an endpoint configuration changes
|
||||
refreshActiveScimEndpoints();
|
||||
groupScimClients.forEach(operationToDispatch);
|
||||
}
|
||||
|
||||
public void dispatchUserModificationToOne(ComponentModel scimServerConfiguration, Consumer<UserScimClient> operationToDispatch) {
|
||||
// TODO should not be required to launch a refresh here : we should refresh clients only if an endpoint configuration changes
|
||||
refreshActiveScimEndpoints();
|
||||
|
||||
// Scim client should already have been created
|
||||
Optional<UserScimClient> matchingClient = userScimClients.stream().filter(u -> u.getConfiguration().getId().equals(scimServerConfiguration.getId())).findFirst();
|
||||
if (matchingClient.isPresent()) {
|
||||
operationToDispatch.accept(matchingClient.get());
|
||||
} else {
|
||||
logger.error("[SCIM] Could not find a Scim Client matching endpoint configuration" + scimServerConfiguration.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void dispatchGroupModificationToOne(ComponentModel scimServerConfiguration, Consumer<GroupScimClient> operationToDispatch) {
|
||||
// TODO should not be required to launch a refresh here : we should refresh clients only if an endpoint configuration changes
|
||||
refreshActiveScimEndpoints();
|
||||
|
||||
// Scim client should already have been created
|
||||
Optional<GroupScimClient> matchingClient = groupScimClients.stream().filter(u -> u.getConfiguration().getId().equals(scimServerConfiguration.getId())).findFirst();
|
||||
if (matchingClient.isPresent()) {
|
||||
operationToDispatch.accept(matchingClient.get());
|
||||
} else {
|
||||
logger.error("[SCIM] Could not find a Scim Client matching endpoint configuration" + scimServerConfiguration.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,6 +275,11 @@ public class UserScimClient implements ScimClientInterface<UserModel> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScrimProviderConfiguration getConfiguration() {
|
||||
return this.scimProviderConfiguration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
|
Loading…
Reference in a new issue