Skip to content
Snippets Groups Projects
Verified Commit fd672971 authored by Hugo Renard's avatar Hugo Renard
Browse files

fix and add config via federation

parent f2dbb59e
No related branches found
No related tags found
No related merge requests found
...@@ -19,23 +19,24 @@ import javax.ws.rs.client.Client; ...@@ -19,23 +19,24 @@ import javax.ws.rs.client.Client;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import sh.libre.scim.jpa.ScimResource; import sh.libre.scim.jpa.ScimResource;
public class ScimClient { public class ScimClient {
final Logger LOGGER = Logger.getLogger(ScimClient.class); final private Logger LOGGER = Logger.getLogger(ScimClient.class);
final Client client = ResteasyClientBuilder.newClient(); final private Client client = ResteasyClientBuilder.newClient();
final ScimService scimService; final private ScimService scimService;
final RetryRegistry registry; final private RetryRegistry registry;
final String name; final private String name;
final String realmId; final private KeycloakSession session;
final EntityManager entityManager;
public ScimClient(String name, String url, String realmId, EntityManager entityManager) { public ScimClient(String name, String url, KeycloakSession session) {
this.name = name; this.name = name;
this.realmId = realmId;
this.entityManager = entityManager; this.session = session;
var target = client.target(url); var target = client.target(url);
scimService = new ScimService(target); scimService = new ScimService(target);
...@@ -46,6 +47,14 @@ public class ScimClient { ...@@ -46,6 +47,14 @@ public class ScimClient {
registry = RetryRegistry.of(retryConfig); registry = RetryRegistry.of(retryConfig);
} }
private EntityManager getEM() {
return session.getProvider(JpaConnectionProvider.class).getEntityManager();
}
private String getRealmId() {
return session.getContext().getRealm().getId();
}
public void createUser(UserModel kcUser) { public void createUser(UserModel kcUser) {
LOGGER.info("Create User"); LOGGER.info("Create User");
var user = toUser(kcUser); var user = toUser(kcUser);
...@@ -58,7 +67,7 @@ public class ScimClient { ...@@ -58,7 +67,7 @@ public class ScimClient {
} }
}); });
var scimUser = toScimUser(spUser); var scimUser = toScimUser(spUser);
entityManager.persist(scimUser); getEM().persist(scimUser);
} }
public void replaceUser(UserModel kcUser) { public void replaceUser(UserModel kcUser) {
...@@ -80,7 +89,7 @@ public class ScimClient { ...@@ -80,7 +89,7 @@ public class ScimClient {
} }
}); });
} catch (NoResultException e) { } catch (NoResultException e) {
LOGGER.warnf("Failde to replce user %s, scim mapping not found", kcUser.getId()); LOGGER.warnf("Failde to repalce user %s, scim mapping not found", kcUser.getId());
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e); LOGGER.error(e);
} }
...@@ -99,16 +108,16 @@ public class ScimClient { ...@@ -99,16 +108,16 @@ public class ScimClient {
} }
return ""; return "";
}); });
entityManager.remove(resource); getEM().remove(resource);
} catch (NoResultException e) { } catch (NoResultException e) {
LOGGER.warnf("Failde to replce user %s, scim mapping not found", userId); LOGGER.warnf("Failde to delete user %s, scim mapping not found", userId);
} }
} }
private TypedQuery<ScimResource> queryUser(String query) { private TypedQuery<ScimResource> queryUser(String query) {
return entityManager return getEM()
.createNamedQuery(query, ScimResource.class) .createNamedQuery(query, ScimResource.class)
.setParameter("realmId", realmId) .setParameter("realmId", getRealmId())
.setParameter("type", "Users") .setParameter("type", "Users")
.setParameter("serviceProvider", name); .setParameter("serviceProvider", name);
} }
...@@ -120,7 +129,7 @@ public class ScimClient { ...@@ -120,7 +129,7 @@ public class ScimClient {
private ScimResource scimUser() { private ScimResource scimUser() {
var resource = new ScimResource(); var resource = new ScimResource();
resource.setType("Users"); resource.setType("Users");
resource.setRealmId(realmId); resource.setRealmId(getRealmId());
resource.setServiceProvider(name); resource.setServiceProvider(name);
return resource; return resource;
} }
......
package sh.libre.scim.core; package sh.libre.scim.core;
import java.util.ArrayList;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import javax.persistence.EntityManager;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import sh.libre.scim.storage.ScimStorageProviderFactory;
public class ScimDispatcher { public class ScimDispatcher {
final KeycloakSession session; final private KeycloakSession session;
final EntityManager entityManager; final private Logger LOGGER = Logger.getLogger(ScimDispatcher.class);
final Logger LOGGER = Logger.getLogger(ScimDispatcher.class);
ArrayList<ScimClient> clients = new ArrayList<ScimClient>();
public ScimDispatcher(KeycloakSession session) { public ScimDispatcher(KeycloakSession session) {
this.session = session; this.session = session;
entityManager = session.getProvider(JpaConnectionProvider.class).getEntityManager();
reloadClients();
}
public void reloadClients() {
close();
LOGGER.info("Cleared SCIM Clients");
var realm = session.getContext().getRealm();
clients = new ArrayList<ScimClient>();
var kcClients = session.clients().getClientsStream(realm);
for (var kcClient : kcClients.toList()) {
var endpoint = kcClient.getAttribute("scim-endpoint");
var name = kcClient.getAttribute("scim-name");
if (endpoint != "") {
if (name == "") {
name = kcClient.getName();
}
clients.add(new ScimClient(
name,
endpoint,
realm.getId(),
entityManager));
LOGGER.infof("Added %s SCIM Client (%s)", name, endpoint);
}
}
}
public void close() {
for (var client : clients) {
client.close();
}
} }
public void run(Consumer<ScimClient> f) { public void run(Consumer<ScimClient> f) {
for (var client : clients) { session.getContext().getRealm().getComponentsStream()
f.accept(client); .filter((m) -> {
} return ScimStorageProviderFactory.ID.equals(m.getProviderId());
})
.forEach(m -> {
LOGGER.infof("%s %s %s %s", m.getId(), m.getName(), m.getProviderId(), m.getProviderType());
var client = new ScimClient(m.getName(), m.get("endpoint"), session);
try {
f.accept(client);
} finally {
client.close();
}
});
} }
} }
...@@ -20,12 +20,10 @@ public class ScimEventListenerProvider implements EventListenerProvider { ...@@ -20,12 +20,10 @@ public class ScimEventListenerProvider implements EventListenerProvider {
public ScimEventListenerProvider(KeycloakSession session) { public ScimEventListenerProvider(KeycloakSession session) {
this.session = session; this.session = session;
dispatcher = new ScimDispatcher(session); dispatcher = new ScimDispatcher(session);
} }
@Override @Override
public void close() { public void close() {
dispatcher.close();
} }
@Override @Override
...@@ -45,9 +43,6 @@ public class ScimEventListenerProvider implements EventListenerProvider { ...@@ -45,9 +43,6 @@ public class ScimEventListenerProvider implements EventListenerProvider {
@Override @Override
public void onEvent(AdminEvent event, boolean includeRepresentation) { public void onEvent(AdminEvent event, boolean includeRepresentation) {
if (event.getResourceType() == ResourceType.CLIENT) {
dispatcher.reloadClients();
}
if (event.getResourceType() == ResourceType.USER) { if (event.getResourceType() == ResourceType.USER) {
var userId = event.getResourcePath().replace("users/", ""); var userId = event.getResourcePath().replace("users/", "");
LOGGER.infof("%s %s", userId, event.getOperationType()); LOGGER.infof("%s %s", userId, event.getOperationType());
......
...@@ -35,16 +35,16 @@ public class ScimResource { ...@@ -35,16 +35,16 @@ public class ScimResource {
@Column(name = "LOCAL_ID", nullable = false) @Column(name = "LOCAL_ID", nullable = false)
private String localId; private String localId;
public ScimResource() { // public ScimResource() {
} // }
public ScimResource(String realmId, String serviceProvider, String type, String remoteId, String localId) { // public ScimResource(String realmId, String serviceProvider, String type, String remoteId, String localId) {
this.realmId = realmId; // this.realmId = realmId;
this.serviceProvider = serviceProvider; // this.serviceProvider = serviceProvider;
this.type = type; // this.type = type;
this.remoteId = remoteId; // this.remoteId = remoteId;
this.localId = localId; // this.localId = localId;
} // }
public String getRealmId() { public String getRealmId() {
return realmId; return realmId;
......
...@@ -4,13 +4,13 @@ import java.util.List; ...@@ -4,13 +4,13 @@ import java.util.List;
import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider; import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
import java.util.Arrays; import java.util.Collections;
public class ScimResourceProvider implements JpaEntityProvider { public class ScimResourceProvider implements JpaEntityProvider {
@Override @Override
public List<Class<?>> getEntities() { public List<Class<?>> getEntities() {
return Arrays.asList(ScimResource.class); return Collections.singletonList(ScimResource.class);
} }
@Override @Override
......
package sh.libre.scim.storage;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
public class ScimStorageProvider implements UserStorageProvider, UserRegistrationProvider {
@Override
public void close() {
}
@Override
public UserModel addUser(RealmModel realm, String username) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
// TODO Auto-generated method stub
return false;
}
}
package sh.libre.scim.storage;
import java.util.List;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderConfigurationBuilder;
import org.keycloak.storage.UserStorageProviderFactory;
public class ScimStorageProviderFactory implements UserStorageProviderFactory<ScimStorageProvider> {
public final static String ID = "scim";
protected static final List<ProviderConfigProperty> configMetadata;
static {
configMetadata = ProviderConfigurationBuilder.create()
.property()
.name("endpoint")
.type(ProviderConfigProperty.STRING_TYPE)
.label("SCIM 2.0 endpoint")
.helpText("External SCIM 2.0 base " +
"URL (/ServiceProviderConfig /Schemas and /ResourcesTypes should be accessible)")
.add()
.build();
}
@Override
public ScimStorageProvider create(KeycloakSession session, ComponentModel model) {
return new ScimStorageProvider();
}
@Override
public String getId() {
return ID;
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return configMetadata;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-services" />
<module name="org.keycloak.keycloak-model-jpa" />
<module name="org.hibernate" />
</dependencies>
</deployment>
</jboss-deployment-structure>
sh.libre.scim.storage.ScimStorageProviderFactory
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment