diff --git a/src/main/java/sh/libre/scim/core/Adapter.java b/src/main/java/sh/libre/scim/core/Adapter.java index 2f8f40cb44e38ce77eb00a8a3c0a824d8f6543cf..2de3124155333bff02280a79ce2a332d0322a6af 100644 --- a/src/main/java/sh/libre/scim/core/Adapter.java +++ b/src/main/java/sh/libre/scim/core/Adapter.java @@ -10,7 +10,6 @@ import org.jboss.logging.Logger; import org.keycloak.connections.jpa.JpaConnectionProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RoleMapperModel; - import sh.libre.scim.jpa.ScimResource; public abstract class Adapter<M extends RoleMapperModel, S extends com.unboundid.scim2.common.ScimResource> { @@ -124,7 +123,7 @@ public abstract class Adapter<M extends RoleMapperModel, S extends com.unboundid public abstract Boolean tryToMap(); public abstract void createEntity(); - + public abstract Stream<M> getResourceStream(); public abstract Boolean skipRefresh(); diff --git a/src/main/java/sh/libre/scim/core/ScimClient.java b/src/main/java/sh/libre/scim/core/ScimClient.java index cd6ac1d2bf7d254619dfdc3cb707561221b3a049..702ff39ba2317ee877670c870fb87c221815de56 100644 --- a/src/main/java/sh/libre/scim/core/ScimClient.java +++ b/src/main/java/sh/libre/scim/core/ScimClient.java @@ -38,12 +38,12 @@ public class ScimClient { var target = client.target(model.get("endpoint")); switch (model.get("auth-mode")) { case "BEARER": - target = target.register(new BearerAuthentication(model.get("auth-bearer-token"))); + target = target.register(new BearerAuthentication(model.get("auth-pass"))); break; case "BASIC_AUTH": target = target.register(new BasicAuthentication( - model.get("auth-basic-auth-user"), - model.get("auth-basic-auth-pass"))); + model.get("auth-user"), + model.get("auth-pass"))); } scimService = new ScimService(target); diff --git a/src/main/java/sh/libre/scim/core/ScimDispatcher.java b/src/main/java/sh/libre/scim/core/ScimDispatcher.java index db00e5842aa952d525c9c57a1c4588fc433e043a..c8beede1982ff823db5a6974dd195dc999328907 100644 --- a/src/main/java/sh/libre/scim/core/ScimDispatcher.java +++ b/src/main/java/sh/libre/scim/core/ScimDispatcher.java @@ -7,6 +7,9 @@ import org.keycloak.models.KeycloakSession; import sh.libre.scim.storage.ScimStorageProviderFactory; public class ScimDispatcher { + public static final String SCOPE_USER = "user"; + public static final String SCOPE_GROUP = "group"; + final private KeycloakSession session; final private Logger LOGGER = Logger.getLogger(ScimDispatcher.class); @@ -14,10 +17,10 @@ public class ScimDispatcher { this.session = session; } - public void run(Consumer<ScimClient> f) { + public void run(String scope, Consumer<ScimClient> f) { session.getContext().getRealm().getComponentsStream() .filter((m) -> { - return ScimStorageProviderFactory.ID.equals(m.getProviderId()) && m.get("enabled").equals("true"); + return ScimStorageProviderFactory.ID.equals(m.getProviderId()) && m.get("enabled").equals("true") && m.get("propagation-"+scope).equals("true"); }) .forEach(m -> { LOGGER.infof("%s %s %s %s", m.getId(), m.getName(), m.getProviderId(), m.getProviderType()); diff --git a/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java b/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java index 58d791c3df871ed922487a84ddd10c6297ce4f4a..95efe5aa7b27d9cd277f56110faeb1b550f06e7d 100644 --- a/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java +++ b/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java @@ -35,14 +35,14 @@ public class ScimEventListenerProvider implements EventListenerProvider { public void onEvent(Event event) { if (event.getType() == EventType.REGISTER) { var user = getUser(event.getUserId()); - dispatcher.run((client) -> client.create(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.create(UserAdapter.class, user)); } if (event.getType() == EventType.UPDATE_EMAIL || event.getType() == EventType.UPDATE_PROFILE) { var user = getUser(event.getUserId()); - dispatcher.run((client) -> client.replace(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.replace(UserAdapter.class, user)); } if (event.getType() == EventType.DELETE_ACCOUNT) { - dispatcher.run((client) -> client.delete(UserAdapter.class, event.getUserId())); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.delete(UserAdapter.class, event.getUserId())); } } @@ -53,14 +53,14 @@ public class ScimEventListenerProvider implements EventListenerProvider { LOGGER.infof("%s %s", userId, event.getOperationType()); if (event.getOperationType() == OperationType.CREATE) { var user = getUser(userId); - dispatcher.run((client) -> client.create(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.create(UserAdapter.class, user)); } if (event.getOperationType() == OperationType.UPDATE) { var user = getUser(userId); - dispatcher.run((client) -> client.replace(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.replace(UserAdapter.class, user)); } if (event.getOperationType() == OperationType.DELETE) { - dispatcher.run((client) -> client.delete(UserAdapter.class, userId)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.delete(UserAdapter.class, userId)); } } if (event.getResourceType() == ResourceType.GROUP) { @@ -68,14 +68,14 @@ public class ScimEventListenerProvider implements EventListenerProvider { LOGGER.infof("%s %s", event.getResourcePath(), event.getOperationType()); if (event.getOperationType() == OperationType.CREATE) { var group = getGroup(groupId); - dispatcher.run((client) -> client.create(GroupAdapter.class, group)); + dispatcher.run(ScimDispatcher.SCOPE_GROUP, (client) -> client.create(GroupAdapter.class, group)); } if (event.getOperationType() == OperationType.UPDATE) { var group = getGroup(groupId); - dispatcher.run((client) -> client.replace(GroupAdapter.class, group)); + dispatcher.run(ScimDispatcher.SCOPE_GROUP, (client) -> client.replace(GroupAdapter.class, group)); } if (event.getOperationType() == OperationType.DELETE) { - dispatcher.run((client) -> client.delete(GroupAdapter.class, groupId)); + dispatcher.run(ScimDispatcher.SCOPE_GROUP, (client) -> client.delete(GroupAdapter.class, groupId)); } } if (event.getResourceType() == ResourceType.GROUP_MEMBERSHIP) { @@ -86,9 +86,9 @@ public class ScimEventListenerProvider implements EventListenerProvider { var groupId = matcher.group(2); LOGGER.infof("%s %s from %s", event.getOperationType(), userId, groupId); var group = getGroup(groupId); - dispatcher.run((client) -> client.replace(GroupAdapter.class, group)); + dispatcher.run(ScimDispatcher.SCOPE_GROUP, (client) -> client.replace(GroupAdapter.class, group)); var user = getUser(userId); - dispatcher.run((client) -> client.replace(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.replace(UserAdapter.class, user)); } } if (event.getResourceType() == ResourceType.REALM_ROLE_MAPPING) { @@ -100,11 +100,11 @@ public class ScimEventListenerProvider implements EventListenerProvider { LOGGER.infof("%s %s %s roles", event.getOperationType(), type, id); if (type.equals("users")) { var user = getUser(id); - dispatcher.run((client) -> client.replace(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.replace(UserAdapter.class, user)); } else if (type.equals("groups")) { var group = getGroup(id); session.users().getGroupMembersStream(session.getContext().getRealm(), group).forEach(user -> { - dispatcher.run((client) -> client.replace(UserAdapter.class, user)); + dispatcher.run(ScimDispatcher.SCOPE_USER, (client) -> client.replace(UserAdapter.class, user)); }); } } diff --git a/src/main/java/sh/libre/scim/storage/ScimStorageProviderFactory.java b/src/main/java/sh/libre/scim/storage/ScimStorageProviderFactory.java index 3f18b7bd3405396c0cdb4b74f078d8140ed575e9..505d884122bedd85973e47ab4bd0a7445ce1bd29 100644 --- a/src/main/java/sh/libre/scim/storage/ScimStorageProviderFactory.java +++ b/src/main/java/sh/libre/scim/storage/ScimStorageProviderFactory.java @@ -52,24 +52,32 @@ public class ScimStorageProviderFactory .type(ProviderConfigProperty.LIST_TYPE) .label("Auth mode") .helpText("Select the authorization mode") - .options("NONE", "BEARER", "BASIC_AUTH") + .options("NONE", "BASIC_AUTH", "BEARER") .defaultValue("NONE") .add() .property() - .name("auth-bearer-token") + .name("auth-user") + .type(ProviderConfigProperty.STRING_TYPE) + .label("Auth username") + .helpText("Required for basic authentification.") + .add() + .property() + .name("auth-pass") .type(ProviderConfigProperty.PASSWORD) - .label("Bearer token") - .helpText("Add a bearer token in the authorization header") + .label("Auth password/token") + .helpText("Password or token required for basic or bearer authentification.") .add() .property() - .name("auth-basic-auth-user") - .type(ProviderConfigProperty.STRING_TYPE) - .label("BasicAuth user") + .name("propagation-user") + .type(ProviderConfigProperty.BOOLEAN_TYPE) + .label("Enable user propagation") + .defaultValue("true") .add() .property() - .name("auth-basic-auth-pass") - .type(ProviderConfigProperty.PASSWORD) - .label("BasicAuth password") + .name("propagation-group") + .type(ProviderConfigProperty.BOOLEAN_TYPE) + .label("Enable group propagation") + .defaultValue("true") .add() .property() .name("sync-import") @@ -120,8 +128,12 @@ public class ScimStorageProviderFactory RealmModel realm = session.realms().getRealm(realmId); session.getContext().setRealm(realm); var client = new ScimClient(model, session); - client.sync(UserAdapter.class, result); - client.sync(GroupAdapter.class, result); + if (model.get("propagation-user").equals("true")) { + client.sync(UserAdapter.class, result); + } + if (model.get("propagation-group").equals("true")) { + client.sync(GroupAdapter.class, result); + } client.close(); }