commit
6714e2b87f
97 changed files with 1354 additions and 1355 deletions
|
@ -5,10 +5,8 @@ import org.keycloak.models.ClientModel;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.provider.ProviderFactoryLoader;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.audit;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuditListenerSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "audit-listener";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return AuditListener.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return AuditListenerFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.audit;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuditProviderSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "audit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return AuditProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return AuditProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
org.keycloak.audit.AuditProviderSpi
|
||||
org.keycloak.audit.AuditListenerSpi
|
|
@ -1,10 +1,10 @@
|
|||
package org.keycloak.audit.log;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.AuditListenerFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -21,7 +21,7 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,9 +33,4 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
|||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.keycloak.audit.jpa;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
|
@ -22,7 +22,7 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store");
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,4 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
|
|||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,13 +2,16 @@ package org.keycloak.audit.mongo;
|
|||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteConcern;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -29,11 +32,28 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
try {
|
||||
client = new MongoClient(System.getProperty(MONGO_HOST, "localhost"), Integer.parseInt(System.getProperty(MONGO_PORT, "27017")));
|
||||
String host = config.get("host", ServerAddress.defaultHost());
|
||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||
String dbName = config.get("db", "keycloak-audit");
|
||||
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||
|
||||
String user = config.get("user");
|
||||
String password = config.get("password");
|
||||
if (user != null && password != null) {
|
||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||
} else {
|
||||
client = new MongoClient(host, port);
|
||||
}
|
||||
|
||||
client.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
|
||||
db = client.getDB(System.getProperty(MONGO_DB_NAME, "keycloak-audit"));
|
||||
db = client.getDB(dbName);
|
||||
|
||||
if (clearOnStartup) {
|
||||
db.getCollection("audit").drop();
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -49,9 +69,4 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
|
|||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactoryLoader;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -23,9 +24,14 @@ public abstract class AbstractAuditProviderTest {
|
|||
|
||||
@Before
|
||||
public void before() {
|
||||
ProviderFactoryLoader<AuditProvider> loader = ProviderFactoryLoader.create(AuditProviderFactory.class);
|
||||
factory = loader.find(getProviderId());
|
||||
factory.init();
|
||||
String providerId = getProviderId();
|
||||
ServiceLoader<AuditProviderFactory> factories = ServiceLoader.load(AuditProviderFactory.class);
|
||||
for (AuditProviderFactory f : factories) {
|
||||
if (f.getId().equals(providerId)) {
|
||||
factory = f;
|
||||
factory.init(Config.scope("audit", providerId));
|
||||
}
|
||||
}
|
||||
|
||||
provider = factory.create(null);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuthenticationSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "authentication";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return AuthenticationProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return AuthenticationProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.authentication.AuthenticationSpi
|
|
@ -1,10 +1,10 @@
|
|||
package org.keycloak.authentication.model;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -17,7 +17,7 @@ public class ExternalModelAuthenticationProviderFactory implements Authenticatio
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,8 +29,4 @@ public class ExternalModelAuthenticationProviderFactory implements Authenticatio
|
|||
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.authentication.model;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
|
@ -16,7 +17,7 @@ public class ModelAuthenticationProviderFactory implements AuthenticationProvide
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,8 +29,4 @@ public class ModelAuthenticationProviderFactory implements AuthenticationProvide
|
|||
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,25 @@
|
|||
package org.keycloak.authentication.picketlink;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.authentication.AuthProviderStatus;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthProviderStatus;
|
||||
import org.keycloak.authentication.AuthUser;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
import org.picketlink.idm.IdentityManagementException;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.PartitionManager;
|
||||
import org.picketlink.idm.credential.Credentials;
|
||||
import org.picketlink.idm.credential.Password;
|
||||
import org.picketlink.idm.credential.UsernamePasswordCredentials;
|
||||
import org.picketlink.idm.model.basic.BasicModel;
|
||||
import org.picketlink.idm.model.basic.User;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AuthenticationProvider, which delegates authentication to picketlink
|
||||
*
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.authentication.picketlink;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
|
@ -17,7 +18,7 @@ public class PicketlinkAuthenticationProviderFactory implements AuthenticationPr
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,8 +30,4 @@ public class PicketlinkAuthenticationProviderFactory implements AuthenticationPr
|
|||
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
129
core/src/main/java/org/keycloak/Config.java
Normal file
129
core/src/main/java/org/keycloak/Config.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
package org.keycloak;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class Config {
|
||||
|
||||
private static ConfigProvider configProvider = new SystemPropertiesConfigProvider();
|
||||
|
||||
public static void init(ConfigProvider configProvider) {
|
||||
Config.configProvider = configProvider;
|
||||
}
|
||||
|
||||
public static String getAdminRealm() {
|
||||
return configProvider.scope("admin").get("realm", "keycloak-admin");
|
||||
}
|
||||
|
||||
public static String getProvider(String spi) {
|
||||
return configProvider.getProvider(spi);
|
||||
}
|
||||
|
||||
public static Scope scope(String... scope) {
|
||||
return configProvider.scope(scope);
|
||||
}
|
||||
|
||||
public static interface ConfigProvider {
|
||||
|
||||
String getProvider(String spi);
|
||||
|
||||
Scope scope(String... scope);
|
||||
|
||||
}
|
||||
|
||||
public static class SystemPropertiesConfigProvider implements ConfigProvider {
|
||||
|
||||
@Override
|
||||
public String getProvider(String spi) {
|
||||
return System.getProperties().getProperty("keycloak." + spi + ".provider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope scope(String... scope) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("keycloak.");
|
||||
for (String s : scope) {
|
||||
sb.append(s);
|
||||
sb.append(".");
|
||||
}
|
||||
return new SystemPropertiesScope(sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SystemPropertiesScope implements Scope {
|
||||
|
||||
private String prefix;
|
||||
|
||||
public SystemPropertiesScope(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key, String defaultValue) {
|
||||
return System.getProperty(prefix + key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(String key) {
|
||||
return getInt(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(String key, Integer defaultValue) {
|
||||
String v = get(key, null);
|
||||
return v != null ? Integer.parseInt(v) : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key) {
|
||||
return getLong(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key, Long defaultValue) {
|
||||
String v = get(key, null);
|
||||
return v != null ? Long.parseLong(v) : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key) {
|
||||
return getBoolean(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||
String v = get(key, null);
|
||||
return v != null ? Boolean.parseBoolean(v) : defaultValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public static interface Scope {
|
||||
|
||||
String get(String key);
|
||||
|
||||
String get(String key, String defaultValue);
|
||||
|
||||
Integer getInt(String key);
|
||||
|
||||
Integer getInt(String key, Integer defaultValue);
|
||||
|
||||
Long getLong(String key);
|
||||
|
||||
Long getLong(String key, Long defaultValue);
|
||||
|
||||
Boolean getBoolean(String key);
|
||||
|
||||
Boolean getBoolean(String key, Boolean defaultValue);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package org.keycloak.provider;
|
||||
|
||||
import org.keycloak.Config;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
|
@ -7,12 +9,10 @@ public interface ProviderFactory<T extends Provider> {
|
|||
|
||||
public T create(ProviderSession providerSession);
|
||||
|
||||
public void init();
|
||||
public void init(Config.Scope config);
|
||||
|
||||
public void close();
|
||||
|
||||
public String getId();
|
||||
|
||||
public boolean lazyLoad();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
package org.keycloak.provider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ProviderFactoryLoader<T extends Provider> implements Iterable<ProviderFactory<T>> {
|
||||
|
||||
private final Map<String, ProviderFactory<T>> factories = new HashMap<String, ProviderFactory<T>>();
|
||||
|
||||
private ProviderFactoryLoader(ServiceLoader<? extends ProviderFactory> serviceLoader) {
|
||||
for (ProviderFactory p : serviceLoader) {
|
||||
if (!System.getProperties().containsKey(p.getClass().getName() + ".disabled")) {
|
||||
if (p.lazyLoad()) {
|
||||
p = new LazyProviderFactory(p);
|
||||
}
|
||||
factories.put(p.getId(), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ProviderFactoryLoader create(Class<? extends ProviderFactory> service) {
|
||||
return new ProviderFactoryLoader(ServiceLoader.load(service));
|
||||
}
|
||||
|
||||
public static ProviderFactoryLoader create(Class<? extends ProviderFactory> service, ClassLoader loader) {
|
||||
return new ProviderFactoryLoader(ServiceLoader.load(service, loader));
|
||||
}
|
||||
|
||||
public ProviderFactory find(String id) {
|
||||
return factories.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ProviderFactory<T>> iterator() {
|
||||
return factories.values().iterator();
|
||||
}
|
||||
|
||||
public Set<String> providerIds() {
|
||||
return factories.keySet();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
for (ProviderFactory p : factories.values()) {
|
||||
p.init();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (ProviderFactory p : factories.values()) {
|
||||
p.close();
|
||||
}
|
||||
}
|
||||
|
||||
private class LazyProviderFactory<T extends Provider> implements ProviderFactory<T> {
|
||||
|
||||
private final ProviderFactory<T> factory;
|
||||
|
||||
private volatile boolean initialized = false;
|
||||
|
||||
private LazyProviderFactory(ProviderFactory<T> factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T create(ProviderSession providerSession) {
|
||||
if (!initialized) {
|
||||
factory.init();
|
||||
initialized = true;
|
||||
}
|
||||
return factory.create(providerSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (initialized) {
|
||||
factory.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return factory.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.provider;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
|
@ -11,12 +9,6 @@ public interface ProviderSessionFactory {
|
|||
|
||||
void close();
|
||||
|
||||
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz);
|
||||
|
||||
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id);
|
||||
|
||||
Set<String> providerIds(Class<? extends Provider> clazz);
|
||||
|
||||
void init();
|
||||
|
||||
}
|
||||
|
|
12
core/src/main/java/org/keycloak/provider/Spi.java
Normal file
12
core/src/main/java/org/keycloak/provider/Spi.java
Normal file
|
@ -0,0 +1,12 @@
|
|||
package org.keycloak.provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface Spi {
|
||||
|
||||
public String getName();
|
||||
public Class<? extends Provider> getProviderClass();
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass();
|
||||
|
||||
}
|
263
core/src/main/java/org/keycloak/util/StringPropertyReplacer.java
Normal file
263
core/src/main/java/org/keycloak/util/StringPropertyReplacer.java
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
* Copyright 2005, JBoss Inc., and individual contributors as indicated
|
||||
* by the @authors tag. See the copyright.txt in the distribution for a
|
||||
* full listing of individual contributors.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
package org.keycloak.util;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A utility class for replacing properties in strings.
|
||||
*
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @author <a href="Scott.Stark@jboss.org">Scott Stark</a>
|
||||
* @author <a href="claudio.vesco@previnet.it">Claudio Vesco</a>
|
||||
* @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
|
||||
* @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
|
||||
* @version <tt>$Revision: 2898 $</tt>
|
||||
*/
|
||||
public final class StringPropertyReplacer
|
||||
{
|
||||
/** New line string constant */
|
||||
public static final String NEWLINE = System.getProperty("line.separator", "\n");
|
||||
|
||||
/** File separator value */
|
||||
private static final String FILE_SEPARATOR = File.separator;
|
||||
|
||||
/** Path separator value */
|
||||
private static final String PATH_SEPARATOR = File.pathSeparator;
|
||||
|
||||
/** File separator alias */
|
||||
private static final String FILE_SEPARATOR_ALIAS = "/";
|
||||
|
||||
/** Path separator alias */
|
||||
private static final String PATH_SEPARATOR_ALIAS = ":";
|
||||
|
||||
// States used in property parsing
|
||||
private static final int NORMAL = 0;
|
||||
private static final int SEEN_DOLLAR = 1;
|
||||
private static final int IN_BRACKET = 2;
|
||||
|
||||
/**
|
||||
* Go through the input string and replace any occurance of ${p} with
|
||||
* the System.getProperty(p) value. If there is no such property p defined,
|
||||
* then the ${p} reference will remain unchanged.
|
||||
*
|
||||
* If the property reference is of the form ${p:v} and there is no such property p,
|
||||
* then the default value v will be returned.
|
||||
*
|
||||
* If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
|
||||
* the primary and the secondary properties will be tried in turn, before
|
||||
* returning either the unchanged input, or the default value.
|
||||
*
|
||||
* The property ${/} is replaced with System.getProperty("file.separator")
|
||||
* value and the property ${:} is replaced with System.getProperty("path.separator").
|
||||
*
|
||||
* @param string - the string with possible ${} references
|
||||
* @return the input string with all property references replaced if any.
|
||||
* If there are no valid references the input string will be returned.
|
||||
*/
|
||||
public static String replaceProperties(final String string)
|
||||
{
|
||||
return replaceProperties(string, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through the input string and replace any occurance of ${p} with
|
||||
* the props.getProperty(p) value. If there is no such property p defined,
|
||||
* then the ${p} reference will remain unchanged.
|
||||
*
|
||||
* If the property reference is of the form ${p:v} and there is no such property p,
|
||||
* then the default value v will be returned.
|
||||
*
|
||||
* If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
|
||||
* the primary and the secondary properties will be tried in turn, before
|
||||
* returning either the unchanged input, or the default value.
|
||||
*
|
||||
* The property ${/} is replaced with System.getProperty("file.separator")
|
||||
* value and the property ${:} is replaced with System.getProperty("path.separator").
|
||||
*
|
||||
* @param string - the string with possible ${} references
|
||||
* @param props - the source for ${x} property ref values, null means use System.getProperty()
|
||||
* @return the input string with all property references replaced if any.
|
||||
* If there are no valid references the input string will be returned.
|
||||
*/
|
||||
public static String replaceProperties(final String string, final Properties props)
|
||||
{
|
||||
final char[] chars = string.toCharArray();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
boolean properties = false;
|
||||
int state = NORMAL;
|
||||
int start = 0;
|
||||
for (int i = 0; i < chars.length; ++i)
|
||||
{
|
||||
char c = chars[i];
|
||||
|
||||
// Dollar sign outside brackets
|
||||
if (c == '$' && state != IN_BRACKET)
|
||||
state = SEEN_DOLLAR;
|
||||
|
||||
// Open bracket immediatley after dollar
|
||||
else if (c == '{' && state == SEEN_DOLLAR)
|
||||
{
|
||||
buffer.append(string.substring(start, i - 1));
|
||||
state = IN_BRACKET;
|
||||
start = i - 1;
|
||||
}
|
||||
|
||||
// No open bracket after dollar
|
||||
else if (state == SEEN_DOLLAR)
|
||||
state = NORMAL;
|
||||
|
||||
// Closed bracket after open bracket
|
||||
else if (c == '}' && state == IN_BRACKET)
|
||||
{
|
||||
// No content
|
||||
if (start + 2 == i)
|
||||
{
|
||||
buffer.append("${}"); // REVIEW: Correct?
|
||||
}
|
||||
else // Collect the system property
|
||||
{
|
||||
String value = null;
|
||||
|
||||
String key = string.substring(start + 2, i);
|
||||
|
||||
// check for alias
|
||||
if (FILE_SEPARATOR_ALIAS.equals(key))
|
||||
{
|
||||
value = FILE_SEPARATOR;
|
||||
}
|
||||
else if (PATH_SEPARATOR_ALIAS.equals(key))
|
||||
{
|
||||
value = PATH_SEPARATOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check from the properties
|
||||
if (props != null)
|
||||
value = props.getProperty(key);
|
||||
else
|
||||
value = System.getProperty(key);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
// Check for a default value ${key:default}
|
||||
int colon = key.indexOf(':');
|
||||
if (colon > 0)
|
||||
{
|
||||
String realKey = key.substring(0, colon);
|
||||
if (props != null)
|
||||
value = props.getProperty(realKey);
|
||||
else
|
||||
value = System.getProperty(realKey);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
// Check for a composite key, "key1,key2"
|
||||
value = resolveCompositeKey(realKey, props);
|
||||
|
||||
// Not a composite key either, use the specified default
|
||||
if (value == null)
|
||||
value = key.substring(colon+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No default, check for a composite key, "key1,key2"
|
||||
value = resolveCompositeKey(key, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
properties = true;
|
||||
buffer.append(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append("${");
|
||||
buffer.append(key);
|
||||
buffer.append('}');
|
||||
}
|
||||
|
||||
}
|
||||
start = i + 1;
|
||||
state = NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// No properties
|
||||
if (properties == false)
|
||||
return string;
|
||||
|
||||
// Collect the trailing characters
|
||||
if (start != chars.length)
|
||||
buffer.append(string.substring(start, chars.length));
|
||||
|
||||
// Done
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to resolve a "key" from the provided properties by
|
||||
* checking if it is actually a "key1,key2", in which case
|
||||
* try first "key1", then "key2". If all fails, return null.
|
||||
*
|
||||
* It also accepts "key1," and ",key2".
|
||||
*
|
||||
* @param key the key to resolve
|
||||
* @param props the properties to use
|
||||
* @return the resolved key or null
|
||||
*/
|
||||
private static String resolveCompositeKey(String key, Properties props)
|
||||
{
|
||||
String value = null;
|
||||
|
||||
// Look for the comma
|
||||
int comma = key.indexOf(',');
|
||||
if (comma > -1)
|
||||
{
|
||||
// If we have a first part, try resolve it
|
||||
if (comma > 0)
|
||||
{
|
||||
// Check the first part
|
||||
String key1 = key.substring(0, comma);
|
||||
if (props != null)
|
||||
value = props.getProperty(key1);
|
||||
else
|
||||
value = System.getProperty(key1);
|
||||
}
|
||||
// Check the second part, if there is one and first lookup failed
|
||||
if (value == null && comma < key.length() - 1)
|
||||
{
|
||||
String key2 = key.substring(comma + 1);
|
||||
if (props != null)
|
||||
value = props.getProperty(key2);
|
||||
else
|
||||
value = System.getProperty(key2);
|
||||
}
|
||||
}
|
||||
// Return whatever we've found or null
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -252,12 +252,12 @@ keycloak-war-dist-all-1.0-beta-1-SNAPSHOT/
|
|||
First you need to specify that you want to use <literal>mongo</literal> instead of default <literal>jpa</literal> model, and you may also specify
|
||||
host, port and name of mongo database. So you can start keycloak with the command like this:
|
||||
<programlisting><![CDATA[
|
||||
./standalone.sh -Dkeycloak.model=mongo -Dkeycloak.mongo.host=localhost
|
||||
-Dkeycloak.mongo.port=27017 -Dkeycloak.mongo.db=keycloak
|
||||
./standalone.sh -Dkeycloak.model=mongo -Dkeycloak.model.mongo.host=localhost
|
||||
-Dkeycloak.model.mongoport=27017 -Dkeycloak.model.mongo.db=keycloak
|
||||
]]></programlisting>
|
||||
Note that when you install MongoDB on your laptop, it's usually on localhost/270717 by default. That's why properties
|
||||
<literal>keycloak.mongo.host</literal> and <literal>keycloak.mongo.port</literal> are not mandatory, but they already have
|
||||
default values <literal>localhost</literal> and <literal>27017</literal> . Similarly property <literal>keycloak.mongo.db</literal>
|
||||
<literal>keycloak.model.mongo.host</literal> and <literal>keycloak.model.mongo.port</literal> are not mandatory, but they already have
|
||||
default values <literal>localhost</literal> and <literal>27017</literal> . Similarly property <literal>keycloak.model.mongo.db</literal>
|
||||
has default value <literal>keycloak</literal> for name of underlying database. So the example above could be simplified like:
|
||||
<programlisting><![CDATA[
|
||||
./standalone.sh -Dkeycloak.model=mongo
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ExportImportProvider {
|
||||
|
||||
void checkExportImport(KeycloakSessionFactory identitySessionFactory);
|
||||
void checkExportImport(ProviderSessionFactory identitySessionFactory);
|
||||
|
||||
}
|
||||
|
|
|
@ -32,13 +32,6 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>jaxrs-api</artifactId>
|
||||
|
@ -121,6 +114,12 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
|
@ -149,10 +148,10 @@
|
|||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<keycloak.mongo.host>localhost</keycloak.mongo.host>
|
||||
<keycloak.mongo.port>27018</keycloak.mongo.port>
|
||||
<keycloak.mongo.db>keycloak</keycloak.mongo.db>
|
||||
<keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
@ -179,10 +178,10 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
|
||||
<keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
|
||||
<keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
|
||||
<keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
|
||||
<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -207,7 +206,7 @@
|
|||
<goal>start</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<port>${keycloak.mongo.port}</port>
|
||||
<port>${keycloak.model.mongo.port}</port>
|
||||
<logging>file</logging>
|
||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||
</configuration>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ExportImportConfig {
|
||||
|
||||
public static final String ACTION = "keycloak.migration.action";
|
||||
public static final String PROVIDER = "keycloak.migration.provider";
|
||||
public static final String PROVIDER_DEFAULT = "zip";
|
||||
|
||||
// used for "directory" provider
|
||||
public static final String DIR = "keycloak.migration.dir";
|
||||
// used for "zip" provider
|
||||
public static final String FILE = "keycloak.migration.zipFile";
|
||||
public static final String PASSWORD = "keycloak.migration.zipPassword";
|
||||
|
||||
public static String getAction() {
|
||||
return System.getProperty(ACTION);
|
||||
}
|
||||
|
||||
public static void setAction(String exportImportAction) {
|
||||
System.setProperty(ACTION, exportImportAction);
|
||||
}
|
||||
|
||||
public static String getProvider() {
|
||||
return System.getProperty(PROVIDER, PROVIDER_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setProvider(String exportImportProvider) {
|
||||
System.setProperty(PROVIDER, exportImportProvider);
|
||||
}
|
||||
|
||||
public static String getDir() {
|
||||
return System.getProperty(DIR);
|
||||
}
|
||||
|
||||
public static String getZipFile() {
|
||||
return System.getProperty(FILE);
|
||||
}
|
||||
|
||||
public static void setZipFile(String exportImportZipFile) {
|
||||
System.setProperty(FILE, exportImportZipFile);
|
||||
}
|
||||
|
||||
public static String getZipPassword() {
|
||||
return System.getProperty(PASSWORD);
|
||||
}
|
||||
|
||||
public static void setZipPassword(String exportImportZipPassword) {
|
||||
System.setProperty(PASSWORD, exportImportZipPassword);
|
||||
}
|
||||
|
||||
}
|
|
@ -4,10 +4,10 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||
import org.keycloak.exportimport.io.ExportWriter;
|
||||
import org.keycloak.exportimport.io.ImportReader;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
/**
|
||||
|
@ -21,8 +21,8 @@ public class ExportImportProviderImpl implements ExportImportProvider {
|
|||
public static final String ACTION_IMPORT = "import";
|
||||
|
||||
@Override
|
||||
public void checkExportImport(KeycloakSessionFactory identitySessionFactory) {
|
||||
String exportImportAction = Config.getExportImportAction();
|
||||
public void checkExportImport(ProviderSessionFactory providerSessionFactory) {
|
||||
String exportImportAction = ExportImportConfig.getAction();
|
||||
|
||||
boolean export = false;
|
||||
boolean importt = false;
|
||||
|
@ -35,7 +35,8 @@ public class ExportImportProviderImpl implements ExportImportProvider {
|
|||
}
|
||||
|
||||
if (export || importt) {
|
||||
KeycloakSession session = identitySessionFactory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
KeycloakTransaction transaction = session.getTransaction();
|
||||
try {
|
||||
transaction.begin();
|
||||
|
@ -63,13 +64,13 @@ public class ExportImportProviderImpl implements ExportImportProvider {
|
|||
}
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ExportImportIOProvider getProvider() {
|
||||
String providerId = Config.getExportImportProvider();
|
||||
String providerId = ExportImportConfig.getProvider();
|
||||
logger.infof("Requested migration provider: " + providerId);
|
||||
|
||||
Iterable<ExportImportIOProvider> providers = ProviderLoader.load(ExportImportIOProvider.class);
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.keycloak.models.ApplicationModel;
|
|||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.keycloak.exportimport.io.directory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||
import org.keycloak.exportimport.io.ExportWriter;
|
||||
import org.keycloak.exportimport.io.ImportReader;
|
||||
import org.keycloak.models.Config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Export/import into JSON files inside "tmp" directory. This implementation is used mainly for testing
|
||||
|
@ -19,13 +19,13 @@ public class TmpDirExportImportIOProvider implements ExportImportIOProvider {
|
|||
|
||||
@Override
|
||||
public ExportWriter getExportWriter() {
|
||||
String dir = Config.getExportImportDir();
|
||||
String dir = ExportImportConfig.getDir();
|
||||
return dir!=null ? new TmpDirExportWriter(new File(dir)) : new TmpDirExportWriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportReader getImportReader() {
|
||||
String dir = Config.getExportImportDir();
|
||||
String dir = ExportImportConfig.getDir();
|
||||
return dir!=null ? new TmpDirImportReader(new File(dir)) : new TmpDirImportReader();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package org.keycloak.exportimport.io.zip;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||
import org.keycloak.exportimport.io.ExportWriter;
|
||||
import org.keycloak.exportimport.io.ImportReader;
|
||||
import org.keycloak.models.Config;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -22,8 +22,8 @@ public class EncryptedZIPIOProvider implements ExportImportIOProvider {
|
|||
|
||||
@Override
|
||||
public ExportWriter getExportWriter() {
|
||||
String zipFile = Config.getExportImportZipFile();
|
||||
String zipPassword = Config.getExportImportZipPassword();
|
||||
String zipFile = ExportImportConfig.getZipFile();
|
||||
String zipPassword = ExportImportConfig.getZipPassword();
|
||||
logger.infof("Using zip for export: " + zipFile);
|
||||
|
||||
if (zipFile==null || zipPassword==null) {
|
||||
|
@ -35,8 +35,8 @@ public class EncryptedZIPIOProvider implements ExportImportIOProvider {
|
|||
|
||||
@Override
|
||||
public ImportReader getImportReader() {
|
||||
String zipFile = Config.getExportImportZipFile();
|
||||
String zipPassword = Config.getExportImportZipPassword();
|
||||
String zipFile = ExportImportConfig.getZipFile();
|
||||
String zipPassword = ExportImportConfig.getZipPassword();
|
||||
logger.infof("Using zip for import: " + zipFile);
|
||||
|
||||
if (zipFile==null || zipPassword==null) {
|
||||
|
|
|
@ -1,36 +1,43 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.model.test.AbstractModelTest;
|
||||
import org.keycloak.model.test.ImportTest;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class ExportImportTestBase {
|
||||
|
||||
protected KeycloakSessionFactory factory;
|
||||
protected ProviderSessionFactory factory;
|
||||
|
||||
protected ProviderSession providerSession;
|
||||
protected KeycloakSession identitySession;
|
||||
protected RealmManager realmManager;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
System.getProperties().remove("keycloak.model.provider");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportImport() throws Exception {
|
||||
// Init JPA model
|
||||
Config.setModelProvider(getExportModelProvider());
|
||||
factory = KeycloakApplication.createSessionFactory();
|
||||
System.setProperty("keycloak.model.provider", getExportModelProvider());
|
||||
factory = KeycloakApplication.createProviderSessionFactory();
|
||||
|
||||
// Bootstrap admin realm
|
||||
beginTransaction();
|
||||
|
@ -59,8 +66,8 @@ public abstract class ExportImportTestBase {
|
|||
factory.close();
|
||||
|
||||
// Bootstrap mongo session and factory
|
||||
Config.setModelProvider(getImportModelProvider());
|
||||
factory = KeycloakApplication.createSessionFactory();
|
||||
System.setProperty("keycloak.model.provider", getImportModelProvider());
|
||||
factory = KeycloakApplication.createProviderSessionFactory();
|
||||
|
||||
// Full import of previous export into mongo
|
||||
importModel(factory);
|
||||
|
@ -83,19 +90,20 @@ public abstract class ExportImportTestBase {
|
|||
|
||||
protected abstract String getImportModelProvider();
|
||||
|
||||
protected abstract void exportModel(KeycloakSessionFactory factory);
|
||||
protected abstract void exportModel(ProviderSessionFactory factory);
|
||||
|
||||
protected abstract void importModel(KeycloakSessionFactory factory);
|
||||
protected abstract void importModel(ProviderSessionFactory factory);
|
||||
|
||||
protected void beginTransaction() {
|
||||
identitySession = factory.createSession();
|
||||
providerSession = factory.createSession();
|
||||
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
identitySession.getTransaction().begin();
|
||||
realmManager = new RealmManager(identitySession);
|
||||
}
|
||||
|
||||
protected void commitTransaction() {
|
||||
identitySession.getTransaction().commit();
|
||||
identitySession.close();
|
||||
providerSession.close();
|
||||
}
|
||||
|
||||
protected ExportImportProvider getExportImportProvider() {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
/**
|
||||
* Test for full export of data from JPA and import them to Mongo. Using "directory" provider
|
||||
|
@ -22,16 +21,16 @@ public class JPAToMongoExportImportTest extends ExportImportTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void exportModel(KeycloakSessionFactory factory) {
|
||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||
Config.setExportImportProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||
protected void exportModel(ProviderSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||
ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||
getExportImportProvider().checkExportImport(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void importModel(KeycloakSessionFactory factory) {
|
||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||
Config.setExportImportProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||
protected void importModel(ProviderSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||
ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||
getExportImportProvider().checkExportImport(factory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Test for full export of data from Mongo and import them to JPA. Using export into encrypted ZIP and import from it
|
||||
|
@ -27,12 +26,12 @@ public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void exportModel(KeycloakSessionFactory factory) {
|
||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||
Config.setExportImportProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||
protected void exportModel(ProviderSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||
ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||
File zipFile = getZipFile();
|
||||
Config.setExportImportZipFile(zipFile.getAbsolutePath());
|
||||
Config.setExportImportZipPassword("password123");
|
||||
ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
|
||||
ExportImportConfig.setZipPassword("password123");
|
||||
|
||||
if (zipFile.exists()) {
|
||||
zipFile.delete();
|
||||
|
@ -42,12 +41,12 @@ public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void importModel(KeycloakSessionFactory factory) {
|
||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||
Config.setExportImportProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||
protected void importModel(ProviderSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||
ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||
File zipFile = getZipFile();
|
||||
Config.setExportImportZipFile(zipFile.getAbsolutePath());
|
||||
Config.setExportImportZipPassword("password-invalid");
|
||||
ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
|
||||
ExportImportConfig.setZipPassword("password-invalid");
|
||||
|
||||
// Try invalid password
|
||||
try {
|
||||
|
@ -55,7 +54,7 @@ public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
|||
Assert.fail("Not expected to be here. Exception should be thrown");
|
||||
} catch (Exception e) {};
|
||||
|
||||
Config.setExportImportZipPassword("password123");
|
||||
ExportImportConfig.setZipPassword("password123");
|
||||
new ExportImportProviderImpl().checkExportImport(factory);
|
||||
|
||||
if (zipFile.exists()) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.keycloak.freemarker;
|
||||
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -20,7 +20,7 @@ public class ThemeLoader {
|
|||
|
||||
public static Theme createTheme(String name, Theme.Type type) throws FreeMarkerException {
|
||||
if (name == null) {
|
||||
name = Config.getThemeDefault();
|
||||
name = Config.scope("theme").get("default");
|
||||
}
|
||||
|
||||
List<ThemeProvider> providers = new LinkedList();
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
package org.keycloak.theme;
|
||||
|
||||
import org.keycloak.freemarker.Theme;
|
||||
import org.keycloak.freemarker.ThemeLoader;
|
||||
import org.keycloak.freemarker.ThemeProvider;
|
||||
import org.keycloak.models.Config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@ package org.keycloak.theme;
|
|||
|
||||
import org.keycloak.freemarker.Theme;
|
||||
import org.keycloak.freemarker.ThemeProvider;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
@ -19,7 +19,7 @@ public class FolderThemeProvider implements ThemeProvider {
|
|||
private File rootDir;
|
||||
|
||||
public FolderThemeProvider() {
|
||||
String d = Config.getThemeDir();
|
||||
String d = Config.scope("theme").get("dir");
|
||||
if (d != null) {
|
||||
rootDir = new File(d);
|
||||
}
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class Config {
|
||||
|
||||
public static final String ADMIN_REALM_KEY = "keycloak.admin.realm";
|
||||
public static final String ADMIN_REALM_DEFAULT = "keycloak-admin";
|
||||
|
||||
public static final String MODEL_PROVIDER_KEY = "keycloak.model";
|
||||
|
||||
public static final String USER_EXPIRATION_SCHEDULE_KEY = "keycloak.scheduled.clearExpiredUserSessions";
|
||||
public static final String USER_EXPIRATION_SCHEDULE_DEFAULT = String.valueOf(TimeUnit.MINUTES.toMillis(15));
|
||||
|
||||
public static final String AUDIT_PROVIDER_KEY = "keycloak.audit";
|
||||
public static final String AUDIT_PROVIDER_DEFAULT = "jpa";
|
||||
public static final String AUDIT_EXPIRATION_SCHEDULE_KEY = "keycloak.scheduled.clearExpiredAuditEvents";
|
||||
public static final String AUDIT_EXPIRATION_SCHEDULE_DEFAULT = String.valueOf(TimeUnit.MINUTES.toMillis(15));
|
||||
|
||||
public static final String PICKETLINK_PROVIDER_KEY = "keycloak.picketlink";
|
||||
|
||||
public static final String THEME_BASE_KEY = "keycloak.theme.base";
|
||||
public static final String THEME_BASE_DEFAULT = "base";
|
||||
public static final String THEME_DEFAULT_KEY = "keycloak.theme.default";
|
||||
public static final String THEME_DEFAULT_DEFAULT = "keycloak";
|
||||
public static final String THEME_DIR_KEY = "keycloak.theme.dir";
|
||||
public static final String THEME_ADMIN_KEY = "keycloak.theme.admin";
|
||||
public static final String THEME_ADMIN_DEFAULT = "keycloak";
|
||||
|
||||
public static final String JBOSS_SERVER_CONFIG_DIR_KEY = "jboss.server.config.dir";
|
||||
|
||||
public static final String TIMER_PROVIDER_KEY = "keycloak.timer";
|
||||
public static final String TIMER_PROVIDER_DEFAULT = "basic";
|
||||
|
||||
public static final String EXPORT_IMPORT_ACTION = "keycloak.migration.action";
|
||||
public static final String EXPORT_IMPORT_PROVIDER = "keycloak.migration.provider";
|
||||
public static final String EXPORT_IMPORT_PROVIDER_DEFAULT = "zip";
|
||||
// used for "directory" provider
|
||||
public static final String EXPORT_IMPORT_DIR = "keycloak.migration.dir";
|
||||
// used for "zip" provider
|
||||
public static final String EXPORT_IMPORT_ZIP_FILE = "keycloak.migration.zipFile";
|
||||
public static final String EXPORT_IMPORT_ZIP_PASSWORD = "keycloak.migration.zipPassword";
|
||||
|
||||
|
||||
public static String getAdminRealm() {
|
||||
return System.getProperty(ADMIN_REALM_KEY, ADMIN_REALM_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setAdminRealm(String realm) {
|
||||
System.setProperty(ADMIN_REALM_KEY, realm);
|
||||
}
|
||||
|
||||
public static String getAuditProvider() {
|
||||
return System.getProperty(AUDIT_PROVIDER_KEY, AUDIT_PROVIDER_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setAuditProvider(String provider) {
|
||||
System.setProperty(AUDIT_PROVIDER_KEY, provider);
|
||||
}
|
||||
|
||||
public static String getAuditExpirationSchedule() {
|
||||
return System.getProperty(AUDIT_EXPIRATION_SCHEDULE_KEY, AUDIT_EXPIRATION_SCHEDULE_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setAuditExpirationSchedule(String schedule) {
|
||||
System.setProperty(AUDIT_EXPIRATION_SCHEDULE_KEY, schedule);
|
||||
}
|
||||
|
||||
public static String getUserExpirationSchedule() {
|
||||
return System.getProperty(USER_EXPIRATION_SCHEDULE_KEY, USER_EXPIRATION_SCHEDULE_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setUserExpirationSchedule(String schedule) {
|
||||
System.setProperty(USER_EXPIRATION_SCHEDULE_KEY, schedule);
|
||||
}
|
||||
|
||||
public static String getModelProvider() {
|
||||
return System.getProperty(MODEL_PROVIDER_KEY);
|
||||
}
|
||||
|
||||
public static void setModelProvider(String provider) {
|
||||
System.setProperty(MODEL_PROVIDER_KEY, provider);
|
||||
}
|
||||
|
||||
public static String getTimerProvider() {
|
||||
return System.getProperty(TIMER_PROVIDER_KEY, TIMER_PROVIDER_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setTimerProvider(String provider) {
|
||||
System.setProperty(TIMER_PROVIDER_KEY, provider);
|
||||
}
|
||||
|
||||
public static String getIdentityManagerProvider() {
|
||||
return System.getProperty(PICKETLINK_PROVIDER_KEY, "realm");
|
||||
}
|
||||
|
||||
public static void setIdentityManagerProvider(String provider) {
|
||||
System.setProperty(PICKETLINK_PROVIDER_KEY, provider);
|
||||
}
|
||||
|
||||
public static String getThemeDir() {
|
||||
String themeDir = System.getProperty(THEME_DIR_KEY);
|
||||
if (themeDir == null && System.getProperties().containsKey(JBOSS_SERVER_CONFIG_DIR_KEY)) {
|
||||
themeDir = System.getProperty(JBOSS_SERVER_CONFIG_DIR_KEY) + File.separator + "themes";
|
||||
}
|
||||
return themeDir;
|
||||
}
|
||||
|
||||
public static void setThemeDir(String dir) {
|
||||
System.setProperty(THEME_DIR_KEY, dir);
|
||||
}
|
||||
|
||||
public static String getThemeBase() {
|
||||
return System.getProperty(THEME_BASE_KEY, THEME_BASE_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setThemeBase(String baseTheme) {
|
||||
System.setProperty(THEME_BASE_KEY, baseTheme);
|
||||
}
|
||||
|
||||
public static String getThemeDefault() {
|
||||
return System.getProperty(THEME_DEFAULT_KEY, THEME_DEFAULT_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setThemeDefault(String defaultTheme) {
|
||||
System.setProperty(THEME_DEFAULT_KEY, defaultTheme);
|
||||
}
|
||||
|
||||
public static String getThemeAdmin() {
|
||||
return System.getProperty(THEME_ADMIN_KEY, THEME_ADMIN_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setThemeAdmin(String adminTheme) {
|
||||
System.setProperty(THEME_ADMIN_KEY, adminTheme);
|
||||
}
|
||||
|
||||
// EXPORT + IMPORT
|
||||
|
||||
public static String getExportImportAction() {
|
||||
return System.getProperty(EXPORT_IMPORT_ACTION);
|
||||
}
|
||||
|
||||
public static void setExportImportAction(String exportImportAction) {
|
||||
System.setProperty(EXPORT_IMPORT_ACTION, exportImportAction);
|
||||
}
|
||||
|
||||
public static String getExportImportProvider() {
|
||||
return System.getProperty(EXPORT_IMPORT_PROVIDER, EXPORT_IMPORT_PROVIDER_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setExportImportProvider(String exportImportProvider) {
|
||||
System.setProperty(EXPORT_IMPORT_PROVIDER, exportImportProvider);
|
||||
}
|
||||
|
||||
public static String getExportImportDir() {
|
||||
return System.getProperty(EXPORT_IMPORT_DIR);
|
||||
}
|
||||
|
||||
public static void setExportImportDir(String exportImportDir) {
|
||||
System.setProperty(EXPORT_IMPORT_DIR, exportImportDir);
|
||||
}
|
||||
|
||||
public static String getExportImportZipFile() {
|
||||
return System.getProperty(EXPORT_IMPORT_ZIP_FILE);
|
||||
}
|
||||
|
||||
public static void setExportImportZipFile(String exportImportZipFile) {
|
||||
System.setProperty(EXPORT_IMPORT_ZIP_FILE, exportImportZipFile);
|
||||
}
|
||||
|
||||
public static String getExportImportZipPassword() {
|
||||
return System.getProperty(EXPORT_IMPORT_ZIP_PASSWORD);
|
||||
}
|
||||
|
||||
public static void setExportImportZipPassword(String exportImportZipPassword) {
|
||||
System.setProperty(EXPORT_IMPORT_ZIP_PASSWORD, exportImportZipPassword);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface KeycloakSession {
|
||||
public interface KeycloakSession extends Provider {
|
||||
KeycloakTransaction getTransaction();
|
||||
|
||||
RealmModel createRealm(String name);
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface KeycloakSessionFactory {
|
||||
KeycloakSession createSession();
|
||||
public interface KeycloakSessionFactory extends ProviderFactory<KeycloakSession> {
|
||||
KeycloakSession create(ProviderSession providerSession);
|
||||
void close();
|
||||
}
|
||||
|
|
27
model/api/src/main/java/org/keycloak/models/ModelSpi.java
Normal file
27
model/api/src/main/java/org/keycloak/models/ModelSpi.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ModelSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "model";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return KeycloakSession.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return KeycloakSessionFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package org.keycloak.models.utils;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ModelProviderUtils {
|
||||
|
||||
public static final String DEFAULT_MODEL_PROVIDER = "jpa";
|
||||
|
||||
public static Iterable<ModelProvider> getRegisteredProviders() {
|
||||
return ServiceLoader.load(ModelProvider.class);
|
||||
}
|
||||
|
||||
public static ModelProvider getConfiguredModelProvider(Iterable<ModelProvider> providers) {
|
||||
String configuredProvider = Config.getModelProvider();
|
||||
ModelProvider provider = null;
|
||||
|
||||
if (configuredProvider != null) {
|
||||
for (ModelProvider p : providers) {
|
||||
if (p.getId().equals(configuredProvider)) {
|
||||
provider = p;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ModelProvider p : providers) {
|
||||
if (provider == null) {
|
||||
provider = p;
|
||||
}
|
||||
|
||||
if (p.getId().equals(DEFAULT_MODEL_PROVIDER)) {
|
||||
provider = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static ModelProvider getConfiguredModelProvider() {
|
||||
return getConfiguredModelProvider(getRegisteredProviders());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.models.ModelSpi
|
|
@ -30,24 +30,6 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jpa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
|
|
|
@ -1,28 +1,53 @@
|
|||
package org.keycloak.models.jpa;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
|
||||
protected EntityManagerFactory factory;
|
||||
|
||||
public JpaKeycloakSessionFactory(EntityManagerFactory factory) {
|
||||
this.factory = factory;
|
||||
protected EntityManagerFactory emf;
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession createSession() {
|
||||
return new JpaKeycloakSession(factory.createEntityManager());
|
||||
public String getId() {
|
||||
return "jpa";
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession create(ProviderSession providerSession) {
|
||||
return new JpaKeycloakSession(emf.createEntityManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
factory.close();
|
||||
emf.close();
|
||||
}
|
||||
|
||||
// Allows to override some properties in persistence.xml by system properties
|
||||
protected Properties getHibernateProperties() {
|
||||
Properties result = new Properties();
|
||||
|
||||
for (Object property : System.getProperties().keySet()) {
|
||||
if (property.toString().startsWith("hibernate.")) {
|
||||
String propValue = System.getProperty(property.toString());
|
||||
result.put(property, propValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
package org.keycloak.models.jpa;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JpaModelProvider implements ModelProvider {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "jpa";
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSessionFactory createFactory() {
|
||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties());
|
||||
return new JpaKeycloakSessionFactory(emf);
|
||||
|
||||
}
|
||||
|
||||
// Allows to override some properties in persistence.xml by system properties
|
||||
protected Properties getHibernateProperties() {
|
||||
Properties result = new Properties();
|
||||
|
||||
for (Object property : System.getProperties().keySet()) {
|
||||
if (property.toString().startsWith("hibernate.")) {
|
||||
String propValue = System.getProperty(property.toString());
|
||||
result.put(property, propValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.models.jpa.JpaKeycloakSessionFactory
|
|
@ -1 +0,0 @@
|
|||
org.keycloak.models.jpa.JpaModelProvider
|
|
@ -44,18 +44,6 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
|
@ -103,10 +91,10 @@
|
|||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<keycloak.mongo.host>localhost</keycloak.mongo.host>
|
||||
<keycloak.mongo.port>27018</keycloak.mongo.port>
|
||||
<keycloak.mongo.db>keycloak</keycloak.mongo.db>
|
||||
<keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
@ -133,10 +121,10 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
|
||||
<keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
|
||||
<keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
|
||||
<keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
|
||||
<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
|
||||
</systemPropertyVariables>
|
||||
<dependenciesToScan>
|
||||
<dependency>org.keycloak:keycloak-model-tests</dependency>
|
||||
|
@ -164,7 +152,7 @@
|
|||
<goal>start</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<port>${keycloak.mongo.port}</port>
|
||||
<port>${keycloak.model.mongo.port}</port>
|
||||
<logging>file</logging>
|
||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||
</configuration>
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package org.keycloak.models.mongo.keycloak;
|
||||
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
import org.keycloak.models.mongo.keycloak.adapters.MongoKeycloakSessionFactory;
|
||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
|
||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProviderHolder;
|
||||
|
||||
import java.lang.Override;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class MongoModelProvider implements ModelProvider {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "mongo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSessionFactory createFactory() {
|
||||
MongoClientProvider mongoClientProvider = MongoClientProviderHolder.getInstance();
|
||||
return new MongoKeycloakSessionFactory(mongoClientProvider);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
package org.keycloak.models.mongo.keycloak.adapters;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.entities.AuthenticationLinkEntity;
|
||||
|
@ -10,7 +15,6 @@ import org.keycloak.models.entities.RequiredCredentialEntity;
|
|||
import org.keycloak.models.entities.SocialLinkEntity;
|
||||
import org.keycloak.models.mongo.api.MongoStore;
|
||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||
|
@ -18,6 +22,10 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
|||
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* KeycloakSessionFactory implementation based on MongoDB
|
||||
|
@ -42,21 +50,50 @@ public class MongoKeycloakSessionFactory implements KeycloakSessionFactory {
|
|||
MongoUserSessionEntity.class
|
||||
};
|
||||
|
||||
private final MongoClientProvider mongoClientProvider;
|
||||
private final MongoStore mongoStore;
|
||||
private MongoClient client;
|
||||
|
||||
public MongoKeycloakSessionFactory(MongoClientProvider provider) {
|
||||
this.mongoClientProvider = provider;
|
||||
this.mongoStore = new MongoStoreImpl(provider.getDB(), provider.clearCollectionsOnStartup(), MANAGED_ENTITY_TYPES);
|
||||
private MongoStore mongoStore;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "mongo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession createSession() {
|
||||
public void init(Config.Scope config) {
|
||||
try {
|
||||
String host = config.get("host", ServerAddress.defaultHost());
|
||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||
String dbName = config.get("db", "keycloak-audit");
|
||||
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||
|
||||
String user = config.get("user");
|
||||
String password = config.get("password");
|
||||
if (user != null && password != null) {
|
||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||
} else {
|
||||
client = new MongoClient(host, port);
|
||||
}
|
||||
|
||||
DB db = client.getDB(dbName);
|
||||
|
||||
this.mongoStore = new MongoStoreImpl(db, clearOnStartup, MANAGED_ENTITY_TYPES);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession create(ProviderSession providerSession) {
|
||||
return new MongoKeycloakSession(mongoStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.mongoClientProvider.close();
|
||||
this.client.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
package org.keycloak.models.mongo.keycloak.config;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface MongoClientProvider {
|
||||
|
||||
MongoClient getMongoClient();
|
||||
|
||||
DB getDB();
|
||||
|
||||
/**
|
||||
* @return true if collections should be cleared on startup
|
||||
*/
|
||||
boolean clearCollectionsOnStartup();
|
||||
|
||||
void close();
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package org.keycloak.models.mongo.keycloak.config;
|
||||
|
||||
/**
|
||||
* Provides {@link MongoClientProvider} instance
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class MongoClientProviderHolder {
|
||||
|
||||
// Just use static object for now. Default idm is SystemPropsMongoClientProvider
|
||||
private static MongoClientProvider instance = new SystemPropertiesMongoClientProvider();
|
||||
|
||||
public static MongoClientProvider getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void setInstance(MongoClientProvider instance) {
|
||||
MongoClientProviderHolder.instance = instance;
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
package org.keycloak.models.mongo.keycloak.config;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Instance of {@link MongoClientProvider} which reads configuration of MongoDB from system properties
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SystemPropertiesMongoClientProvider implements MongoClientProvider {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(SystemPropertiesMongoClientProvider.class);
|
||||
|
||||
public static final String MONGO_HOST = "keycloak.mongo.host";
|
||||
public static final String MONGO_PORT = "keycloak.mongo.port";
|
||||
public static final String MONGO_DB_NAME = "keycloak.mongo.db";
|
||||
public static final String MONGO_CLEAR_ON_STARTUP = "keycloak.mongo.clearOnStartup";
|
||||
|
||||
// Property names from Liveoak . Those are used as fallback
|
||||
private static final String MONGO_HOST_2 = "mongo.host";
|
||||
private static final String MONGO_PORT_2 = "mongo.port";
|
||||
private static final String MONGO_DB_NAME_2 = "mongo.db";
|
||||
private static final String MONGO_CLEAR_ON_STARTUP_2 = "mongo.clearOnStartup";
|
||||
|
||||
// Port where MongoDB instance is normally started on linux. This port should be used if we're not starting embedded instance
|
||||
private static final String MONGO_DEFAULT_PORT = "27017";
|
||||
|
||||
private MongoClient mongoClient;
|
||||
private DB db;
|
||||
|
||||
@Override
|
||||
public synchronized MongoClient getMongoClient() {
|
||||
if (this.mongoClient == null) {
|
||||
init();
|
||||
}
|
||||
return this.mongoClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DB getDB() {
|
||||
if (mongoClient == null) {
|
||||
init();
|
||||
}
|
||||
return this.db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearCollectionsOnStartup() {
|
||||
return isClearCollectionsOnStartup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
// Assume that client is dedicated just for Keycloak, so close it
|
||||
logger.info("Closing MongoDB client");
|
||||
mongoClient.close();
|
||||
mongoClient = null;
|
||||
db = null;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
try {
|
||||
String host = getMongoHost();
|
||||
int port = getMongoPort();
|
||||
String dbName = getMongoDbName();
|
||||
boolean clearOnStartup = isClearCollectionsOnStartup();
|
||||
|
||||
logger.info(String.format("Configuring MongoStore with: host=%s, port=%d, dbName=%s, clearOnStartup=%b", host, port, dbName, clearOnStartup));
|
||||
|
||||
this.mongoClient = new MongoClient(host, port);
|
||||
this.db = mongoClient.getDB(dbName);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMongoHost() {
|
||||
return getSystemPropertyWithFallback(MONGO_HOST, MONGO_HOST_2, "localhost");
|
||||
}
|
||||
|
||||
public static int getMongoPort() {
|
||||
String portProp = getSystemPropertyWithFallback(MONGO_PORT, MONGO_PORT_2, MONGO_DEFAULT_PORT);
|
||||
return Integer.parseInt(portProp);
|
||||
}
|
||||
|
||||
public static String getMongoDbName() {
|
||||
return getSystemPropertyWithFallback(MONGO_DB_NAME, MONGO_DB_NAME_2, "keycloak");
|
||||
}
|
||||
|
||||
public static boolean isClearCollectionsOnStartup() {
|
||||
String property = getSystemPropertyWithFallback(MONGO_CLEAR_ON_STARTUP, MONGO_CLEAR_ON_STARTUP_2, "false");
|
||||
return "true".equalsIgnoreCase(property);
|
||||
}
|
||||
|
||||
// Check if property propName1 (like "keycloak.mongo.host" is available and if not, then fallback to property "mongo.host" )
|
||||
private static String getSystemPropertyWithFallback(String propName1, String propName2, String defaultValue) {
|
||||
String propValue1 = System.getProperty(propName1);
|
||||
return propValue1!=null ? propValue1 : System.getProperty(propName2, defaultValue);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.models.mongo.keycloak.adapters.MongoKeycloakSessionFactory
|
|
@ -1 +0,0 @@
|
|||
org.keycloak.models.mongo.keycloak.MongoModelProvider
|
|
@ -1,31 +0,0 @@
|
|||
package org.keycloak.models.mongo.test;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoEntity;
|
||||
import org.keycloak.models.mongo.api.MongoField;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class Address {
|
||||
|
||||
private String street;
|
||||
private int number;
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package org.keycloak.models.mongo.test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoField;
|
||||
|
||||
/**
|
||||
* Just to test inheritance
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AddressWithFlats extends Address {
|
||||
|
||||
private List<String> flatNumbers;
|
||||
|
||||
public List<String> getFlatNumbers() {
|
||||
return flatNumbers;
|
||||
}
|
||||
|
||||
public void setFlatNumbers(List<String> flatNumbers) {
|
||||
this.flatNumbers = flatNumbers;
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
package org.keycloak.models.mongo.test;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.QueryBuilder;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.mongo.api.MongoStore;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.models.mongo.impl.context.TransactionMongoStoreInvocationContext;
|
||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
|
||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProviderHolder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class MongoStoreTest {
|
||||
|
||||
private static final Class<?>[] MANAGED_DATA_TYPES = (Class<?>[])new Class<?>[] {
|
||||
Person.class,
|
||||
Address.class,
|
||||
AddressWithFlats.class
|
||||
};
|
||||
|
||||
private MongoClientProvider mongoClientProvider;
|
||||
private MongoStore mongoStore;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
mongoClientProvider = MongoClientProviderHolder.getInstance();
|
||||
mongoStore = new MongoStoreImpl(mongoClientProvider.getDB(), true, MANAGED_DATA_TYPES);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
mongoClientProvider.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mongoModelTest() throws Exception {
|
||||
MongoStoreInvocationContext context = new TransactionMongoStoreInvocationContext(mongoStore);
|
||||
|
||||
// Add some user
|
||||
Person john = new Person();
|
||||
john.setFirstName("john");
|
||||
john.setAge(25);
|
||||
john.setGender(Person.Gender.MALE);
|
||||
|
||||
mongoStore.insertEntity(john, context);
|
||||
|
||||
// Add another user
|
||||
Person mary = new Person();
|
||||
mary.setFirstName("mary");
|
||||
mary.setKids(asList("Peter", "Paul", "Wendy"));
|
||||
|
||||
AddressWithFlats addr1 = new AddressWithFlats();
|
||||
addr1.setStreet("Elm");
|
||||
addr1.setNumber(5);
|
||||
addr1.setFlatNumbers(asList("flat1", "flat2"));
|
||||
AddressWithFlats addr2 = new AddressWithFlats();
|
||||
List<AddressWithFlats> addresses = new ArrayList<AddressWithFlats>();
|
||||
addresses.add(addr1);
|
||||
addresses.add(addr2);
|
||||
|
||||
mary.setAddresses(addresses);
|
||||
mary.setMainAddress(addr1);
|
||||
mary.setGender(Person.Gender.FEMALE);
|
||||
mary.setGenders(asList(Person.Gender.FEMALE));
|
||||
|
||||
mongoStore.insertEntity(mary, context);
|
||||
|
||||
Assert.assertEquals(2, mongoStore.loadEntities(Person.class, new QueryBuilder().get(), context).size());
|
||||
|
||||
// Commit this context
|
||||
context.commit();
|
||||
|
||||
Assert.assertEquals(2, mongoStore.loadEntities(Person.class, new QueryBuilder().get(), context).size());
|
||||
|
||||
DBObject query = new QueryBuilder().and("addresses.flatNumbers").is("flat1").get();
|
||||
List<Person> persons = mongoStore.loadEntities(Person.class, query, context);
|
||||
Assert.assertEquals(1, persons.size());
|
||||
mary = persons.get(0);
|
||||
Assert.assertEquals(mary.getFirstName(), "mary");
|
||||
Assert.assertTrue(mary.getKids().contains("Paul"));
|
||||
Assert.assertEquals(2, mary.getAddresses().size());
|
||||
Assert.assertEquals(AddressWithFlats.class, mary.getAddresses().get(0).getClass());
|
||||
|
||||
// Test push/pull
|
||||
mongoStore.pushItemToList(mary, "kids", "Pauline", true, context);
|
||||
mongoStore.pullItemFromList(mary, "kids", "Paul", context);
|
||||
|
||||
Address addr3 = new Address();
|
||||
addr3.setNumber(6);
|
||||
addr3.setStreet("Broadway");
|
||||
mongoStore.pushItemToList(mary, "addresses", addr3, true, context);
|
||||
|
||||
mary = mongoStore.loadEntity(Person.class, mary.getId(), context);
|
||||
Assert.assertEquals(3, mary.getKids().size());
|
||||
Assert.assertTrue(mary.getKids().contains("Pauline"));
|
||||
Assert.assertFalse(mary.getKids().contains("Paul"));
|
||||
Assert.assertEquals(3, mary.getAddresses().size());
|
||||
Address mainAddress = mary.getMainAddress();
|
||||
Assert.assertEquals("Elm", mainAddress.getStreet());
|
||||
Assert.assertEquals(5, mainAddress.getNumber());
|
||||
Assert.assertEquals(Person.Gender.FEMALE, mary.getGender());
|
||||
Assert.assertTrue(mary.getGenders().contains(Person.Gender.FEMALE));
|
||||
|
||||
|
||||
// Some test of Map (attributes)
|
||||
mary.addAttribute("attr1", "value1");
|
||||
mary.addAttribute("attr2", "value2");
|
||||
mary.addAttribute("attr.some3", "value3");
|
||||
mongoStore.updateEntity(mary, context);
|
||||
|
||||
mary = mongoStore.loadEntity(Person.class, mary.getId(), context);
|
||||
Assert.assertEquals(3, mary.getAttributes().size());
|
||||
|
||||
mary.removeAttribute("attr2");
|
||||
mary.removeAttribute("nonExisting");
|
||||
mongoStore.updateEntity(mary, context);
|
||||
|
||||
mary = mongoStore.loadEntity(Person.class, mary.getId(), context);
|
||||
Assert.assertEquals(2, mary.getAttributes().size());
|
||||
Assert.assertEquals("value1", mary.getAttributes().get("attr1"));
|
||||
Assert.assertEquals("value3", mary.getAttributes().get("attr.some3"));
|
||||
|
||||
context.commit();
|
||||
}
|
||||
|
||||
private <T> List<T> asList(T... objects) {
|
||||
List<T> list = new ArrayList<T>();
|
||||
list.addAll(Arrays.asList(objects));
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
package org.keycloak.models.mongo.test;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoCollection;
|
||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@MongoCollection(collectionName = "persons")
|
||||
public class Person implements MongoIdentifiableEntity {
|
||||
|
||||
private String id;
|
||||
private String firstName;
|
||||
private int age;
|
||||
private List<String> kids;
|
||||
private List<AddressWithFlats> addresses;
|
||||
private Address mainAddress;
|
||||
private Gender gender;
|
||||
private List<Gender> genders;
|
||||
private Map<String, String> attributes = new HashMap<String, String>();
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Gender getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(Gender gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public List<Gender> getGenders() {
|
||||
return genders;
|
||||
}
|
||||
|
||||
public void setGenders(List<Gender> genders) {
|
||||
this.genders = genders;
|
||||
}
|
||||
|
||||
public List<String> getKids() {
|
||||
return kids;
|
||||
}
|
||||
|
||||
public void setKids(List<String> kids) {
|
||||
this.kids = kids;
|
||||
}
|
||||
|
||||
public List<AddressWithFlats> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void setAddresses(List<AddressWithFlats> addresses) {
|
||||
this.addresses = addresses;
|
||||
}
|
||||
|
||||
public Address getMainAddress() {
|
||||
return mainAddress;
|
||||
}
|
||||
|
||||
public void setMainAddress(Address mainAddress) {
|
||||
this.mainAddress = mainAddress;
|
||||
}
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public void addAttribute(String key, String value) {
|
||||
attributes.put(key, value);
|
||||
}
|
||||
|
||||
public void removeAttribute(String key) {
|
||||
attributes.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRemove(MongoStoreInvocationContext invocationContext) {
|
||||
}
|
||||
|
||||
public static enum Gender {
|
||||
MALE, FEMALE
|
||||
}
|
||||
}
|
|
@ -11,10 +11,9 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -28,7 +27,6 @@ import org.keycloak.util.JsonSerialization;
|
|||
*/
|
||||
public class AbstractModelTest {
|
||||
|
||||
protected static KeycloakSessionFactory factory;
|
||||
protected static ProviderSessionFactory providerSessionFactory;
|
||||
|
||||
protected KeycloakSession identitySession;
|
||||
|
@ -37,41 +35,40 @@ public class AbstractModelTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
factory = KeycloakApplication.createSessionFactory();
|
||||
providerSessionFactory = KeycloakApplication.createProviderSessionFactory();
|
||||
|
||||
KeycloakSession identitySession = factory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
try {
|
||||
identitySession.getTransaction().begin();
|
||||
new ApplianceBootstrap().bootstrap(identitySession, "/auth");
|
||||
identitySession.getTransaction().commit();
|
||||
} finally {
|
||||
identitySession.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
providerSessionFactory.close();
|
||||
factory.close();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
identitySession = factory.createSession();
|
||||
providerSession = providerSessionFactory.createSession();
|
||||
|
||||
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
identitySession.getTransaction().begin();
|
||||
realmManager = new RealmManager(identitySession);
|
||||
|
||||
providerSession = providerSessionFactory.createSession();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
identitySession.getTransaction().commit();
|
||||
providerSession.close();
|
||||
identitySession.close();
|
||||
|
||||
identitySession = factory.createSession();
|
||||
providerSession = providerSessionFactory.createSession();
|
||||
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
try {
|
||||
identitySession.getTransaction().begin();
|
||||
|
||||
|
@ -84,7 +81,7 @@ public class AbstractModelTest {
|
|||
|
||||
identitySession.getTransaction().commit();
|
||||
} finally {
|
||||
identitySession.close();
|
||||
providerSession.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -103,8 +100,10 @@ public class AbstractModelTest {
|
|||
}
|
||||
|
||||
protected void resetSession() {
|
||||
identitySession.close();
|
||||
identitySession = factory.createSession();
|
||||
providerSession.close();
|
||||
|
||||
providerSession = providerSessionFactory.createSession();
|
||||
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
identitySession.getTransaction().begin();
|
||||
realmManager = new RealmManager(identitySession);
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
|
|||
realm.setAccessTokenLifespan(1000);
|
||||
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
||||
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
|
||||
protector = new BruteForceProtector(factory);
|
||||
protector = new BruteForceProtector(providerSessionFactory);
|
||||
protector.start();
|
||||
am = new AuthenticationManager(providerSession, protector);
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package org.keycloak.picketlink;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class IdentityManagerSpi implements Spi {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "picketlink-identity-manager";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return IdentityManagerProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return IdentityManagerProviderFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.picketlink.IdentityManagerSpi
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.picketlink.realm;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||
import org.keycloak.picketlink.IdentityManagerProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
@ -20,7 +21,7 @@ public class RealmIdentityManagerProviderFactory implements IdentityManagerProvi
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
partitionManagerRegistry = new PartitionManagerRegistry();
|
||||
}
|
||||
|
||||
|
@ -33,8 +34,4 @@ public class RealmIdentityManagerProviderFactory implements IdentityManagerProvi
|
|||
return "realm";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.resteasy.core.Dispatcher;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
||||
|
@ -22,7 +23,8 @@ public class UpsSecurityApplication extends KeycloakApplication {
|
|||
@Override
|
||||
protected void setupDefaultRealm(String contextPath) {
|
||||
super.setupDefaultRealm(contextPath);
|
||||
KeycloakSession session = factory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
|
||||
// disable master realm by deleting the admin user.
|
||||
|
@ -33,7 +35,7 @@ public class UpsSecurityApplication extends KeycloakApplication {
|
|||
if (admin != null) master.removeUser(admin.getLoginName());
|
||||
session.getTransaction().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -225,6 +225,39 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Mongo dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-mongo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-mongo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-simple-schema</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- export/import -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
|
|
26
server/src/main/resources/META-INF/keycloak-server.json
Normal file
26
server/src/main/resources/META-INF/keycloak-server.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"admin": {
|
||||
"realm": "keycloak-admin"
|
||||
},
|
||||
|
||||
"audit": {
|
||||
"provider": "jpa"
|
||||
},
|
||||
|
||||
"model": {
|
||||
"provider": "jpa"
|
||||
},
|
||||
|
||||
"timer": {
|
||||
"provider": "basic"
|
||||
},
|
||||
|
||||
"theme": {
|
||||
"default": "keycloak",
|
||||
"dir": "${jboss.server.config.dir}/themes"
|
||||
},
|
||||
|
||||
"scheduled": {
|
||||
"interval": 900
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
<properties>
|
||||
<property name="hibernate.hbm2ddl.auto" value="update" />
|
||||
<property name="jboss.as.jpa.managed" value="false" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
|
||||
|
@ -35,6 +36,7 @@
|
|||
|
||||
<properties>
|
||||
<property name="hibernate.hbm2ddl.auto" value="update" />
|
||||
<property name="jboss.as.jpa.managed" value="false" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
|
|
|
@ -6,6 +6,8 @@ import org.keycloak.provider.ProviderSession;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -13,6 +15,7 @@ import java.util.Set;
|
|||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class DefaultProviderSession implements ProviderSession {
|
||||
|
||||
private DefaultProviderSessionFactory factory;
|
||||
private Map<Integer, Provider> providers = new HashMap<Integer, Provider>();
|
||||
|
||||
|
@ -21,8 +24,16 @@ public class DefaultProviderSession implements ProviderSession {
|
|||
}
|
||||
|
||||
public <T extends Provider> T getProvider(Class<T> clazz) {
|
||||
String id = factory.getDefaultProvider(clazz);
|
||||
return id != null ? getProvider(clazz, id) : null;
|
||||
Integer hash = clazz.hashCode();
|
||||
T provider = (T) providers.get(hash);
|
||||
if (provider == null) {
|
||||
ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz);
|
||||
if (providerFactory != null) {
|
||||
provider = providerFactory.create(this);
|
||||
providers.put(hash, provider);
|
||||
}
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
public <T extends Provider> T getProvider(Class<T> clazz, String id) {
|
||||
|
@ -39,15 +50,14 @@ public class DefaultProviderSession implements ProviderSession {
|
|||
}
|
||||
|
||||
public <T extends Provider> Set<String> listProviderIds(Class<T> clazz) {
|
||||
return factory.providerIds(clazz);
|
||||
return factory.getAllProviderIds(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Provider> Set<T> getAllProviders(Class<T> clazz) {
|
||||
Set<String> providerIds = listProviderIds(clazz);
|
||||
Set<T> providers = new HashSet<T>();
|
||||
for (String providerId : providerIds) {
|
||||
providers.add(getProvider(clazz, providerId));
|
||||
for (String id : listProviderIds(clazz)) {
|
||||
providers.add(getProvider(clazz, id));
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
|
|
|
@ -1,71 +1,99 @@
|
|||
package org.keycloak.services;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactoryLoader;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
public class DefaultProviderSessionFactory implements ProviderSessionFactory {
|
||||
|
||||
private Map<Class<? extends Provider>, ProviderFactoryLoader> loaders = new HashMap<Class<? extends Provider>, ProviderFactoryLoader>();
|
||||
private Map<Class<? extends Provider>, String> defaultFactories = new HashMap<Class<? extends Provider>, String>();
|
||||
private static final Logger log = Logger.getLogger(DefaultProviderSessionFactory.class);
|
||||
|
||||
private Map<Class<? extends Provider>, String> provider = new HashMap<Class<? extends Provider>, String>();
|
||||
private Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<Class<? extends Provider>, Map<String, ProviderFactory>>();
|
||||
|
||||
public void init() {
|
||||
for (Spi spi : ServiceLoader.load(Spi.class)) {
|
||||
Map<String, ProviderFactory> factories = new HashMap<String, ProviderFactory>();
|
||||
factoriesMap.put(spi.getProviderClass(), factories);
|
||||
|
||||
String provider = Config.getProvider(spi.getName());
|
||||
if (provider != null) {
|
||||
this.provider.put(spi.getProviderClass(), provider);
|
||||
|
||||
ProviderFactory factory = loadProviderFactory(spi, provider);
|
||||
Config.Scope scope = Config.scope(spi.getName(), provider);
|
||||
factory.init(scope);
|
||||
log.debug("Initialized " + factory.getClass().getName() + " (config = " + scope + ")");
|
||||
|
||||
factories.put(factory.getId(), factory);
|
||||
|
||||
log.info("Loaded SPI " + spi.getName() + " (provider = " + provider + ")");
|
||||
} else {
|
||||
for (ProviderFactory factory : ServiceLoader.load(spi.getProviderFactoryClass())) {
|
||||
Config.Scope scope = Config.scope(spi.getName(), factory.getId());
|
||||
factory.init(scope);
|
||||
log.debug("Initialized " + factory.getClass().getName() + " (config = " + scope + ")");
|
||||
|
||||
factories.put(factory.getId(), factory);
|
||||
}
|
||||
|
||||
if (factories.size() == 1) {
|
||||
provider = factories.values().iterator().next().getId();
|
||||
this.provider.put(spi.getProviderClass(), provider);
|
||||
|
||||
log.info("Loaded SPI " + spi.getName() + " (provider = " + provider + ")");
|
||||
} else {
|
||||
log.info("Loaded SPI " + spi.getName() + " (providers = " + factories.keySet() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ProviderFactory loadProviderFactory(Spi spi, String id) {
|
||||
for (ProviderFactory factory : ServiceLoader.load(spi.getProviderFactoryClass())) {
|
||||
if (factory.getId().equals(id)){
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Failed to find provider " + id + " for " + spi.getName());
|
||||
}
|
||||
|
||||
public ProviderSession createSession() {
|
||||
return new DefaultProviderSession(this);
|
||||
}
|
||||
|
||||
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz) {
|
||||
return getProviderFactory(clazz, provider.get(clazz));
|
||||
}
|
||||
|
||||
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
|
||||
return factoriesMap.get(clazz).get(id);
|
||||
}
|
||||
|
||||
<T extends Provider> Set<String> getAllProviderIds(Class<T> clazz) {
|
||||
Set<String> ids = new HashSet<String>();
|
||||
for (ProviderFactory f : factoriesMap.get(clazz).values()) {
|
||||
ids.add(f.getId());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (ProviderFactoryLoader loader : loaders.values()) {
|
||||
loader.close();
|
||||
for (Map<String, ProviderFactory> factories : factoriesMap.values()) {
|
||||
for (ProviderFactory factory : factories.values()) {
|
||||
factory.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz) {
|
||||
String id = defaultFactories.get(clazz);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
return getProviderFactory(clazz, id);
|
||||
}
|
||||
|
||||
public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
|
||||
ProviderFactoryLoader loader = getLoader(clazz);
|
||||
return loader != null ? loader.find(id) : null;
|
||||
}
|
||||
|
||||
public Set<String> providerIds(Class<? extends Provider> clazz) {
|
||||
ProviderFactoryLoader loader = getLoader(clazz);
|
||||
return loader != null ? loader.providerIds() : null;
|
||||
}
|
||||
|
||||
public String getDefaultProvider(Class<? extends Provider> clazz) {
|
||||
return defaultFactories.get(clazz);
|
||||
}
|
||||
|
||||
public void registerLoader(Class<? extends Provider> clazz, ProviderFactoryLoader loader) {
|
||||
loaders.put(clazz, loader);
|
||||
|
||||
}
|
||||
|
||||
public void registerLoader(Class<? extends Provider> clazz, ProviderFactoryLoader loader, String defaultProvider) {
|
||||
loaders.put(clazz, loader);
|
||||
defaultFactories.put(clazz, defaultProvider);
|
||||
|
||||
}
|
||||
|
||||
public void init() {
|
||||
for (ProviderFactoryLoader l : loaders.values()) {
|
||||
l.init();
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Provider> ProviderFactoryLoader getLoader(Class<T> clazz) {
|
||||
return loaders.get(clazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,9 +32,7 @@ public class KeycloakSessionServletFilter implements Filter {
|
|||
|
||||
ResteasyProviderFactory.pushContext(ProviderSession.class, providerSession);
|
||||
|
||||
KeycloakSessionFactory factory = (KeycloakSessionFactory) servletRequest.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
|
||||
if (factory == null) throw new ServletException("Factory was null");
|
||||
KeycloakSession session = factory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
ResteasyProviderFactory.pushContext(KeycloakSession.class, session);
|
||||
KeycloakTransaction tx = session.getTransaction();
|
||||
ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);
|
||||
|
@ -56,7 +54,6 @@ public class KeycloakSessionServletFilter implements Filter {
|
|||
if (tx.isActive()) tx.rollback();
|
||||
throw ex;
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
ResteasyProviderFactory.clearContextData();
|
||||
}
|
||||
|
|
|
@ -6,14 +6,15 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -26,26 +27,25 @@ public class ApplianceBootstrap {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(ApplianceBootstrap.class);
|
||||
|
||||
public void bootstrap(KeycloakSessionFactory factory, String contextPath) {
|
||||
KeycloakSession session = factory.createSession();
|
||||
public void bootstrap(ProviderSessionFactory factory, String contextPath) {
|
||||
ProviderSession providerSession = factory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
|
||||
try {
|
||||
bootstrap(session, contextPath);
|
||||
session.getTransaction().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void bootstrap(KeycloakSession session, String contextPath) {
|
||||
if (session.getRealm(Config.getAdminRealm()) != null) {
|
||||
String adminRealmName = Config.getAdminRealm();
|
||||
if (session.getRealm(adminRealmName) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String adminRealmName = Config.getAdminRealm();
|
||||
|
||||
logger.info("Initializing " + adminRealmName + " realm");
|
||||
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
|
|
@ -6,6 +6,8 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UsernameLoginFailureModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.services.ClientConnection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -25,7 +27,7 @@ public class BruteForceProtector implements Runnable {
|
|||
|
||||
protected volatile boolean run = true;
|
||||
protected int maxDeltaTimeSeconds = 60 * 60 * 12; // 12 hours
|
||||
protected KeycloakSessionFactory factory;
|
||||
protected ProviderSessionFactory factory;
|
||||
protected CountDownLatch shutdownLatch = new CountDownLatch(1);
|
||||
|
||||
protected volatile long failures;
|
||||
|
@ -73,7 +75,7 @@ public class BruteForceProtector implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
public BruteForceProtector(KeycloakSessionFactory factory) {
|
||||
public BruteForceProtector(ProviderSessionFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
|
@ -160,7 +162,8 @@ public class BruteForceProtector implements Runnable {
|
|||
events.add(take);
|
||||
queue.drainTo(events, TRANSACTION_SIZE);
|
||||
Collections.sort(events); // we sort to avoid deadlock due to ordered updates. Maybe I'm overthinking this.
|
||||
KeycloakSession session = factory.createSession();
|
||||
ProviderSession providerSession = factory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
try {
|
||||
for (LoginEvent event : events) {
|
||||
|
@ -179,7 +182,7 @@ public class BruteForceProtector implements Runnable {
|
|||
}
|
||||
}
|
||||
events.clear();
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed processing event", e);
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.keycloak.models.ApplicationModel;
|
|||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
|
|
|
@ -1,39 +1,30 @@
|
|||
package org.keycloak.services.resources;
|
||||
|
||||
import org.jboss.resteasy.core.Dispatcher;
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.core.Dispatcher;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.SkeletonKeyContextResolver;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.AuditListenerFactory;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
import org.keycloak.exportimport.ExportImportProvider;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactoryLoader;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.DefaultProviderSessionFactory;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.BruteForceProtector;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.SocialRequestManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.resources.admin.AdminRoot;
|
||||
import org.keycloak.models.utils.ModelProviderUtils;
|
||||
import org.keycloak.services.scheduled.ClearExpiredAuditEvents;
|
||||
import org.keycloak.services.scheduled.ClearExpiredUserSessions;
|
||||
import org.keycloak.services.scheduled.ScheduledTaskRunner;
|
||||
import org.keycloak.services.util.JsonConfigProvider;
|
||||
import org.keycloak.timer.TimerProvider;
|
||||
import org.keycloak.timer.TimerProviderFactory;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
|
@ -41,12 +32,13 @@ import javax.servlet.ServletContext;
|
|||
import javax.ws.rs.core.Application;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
@ -63,22 +55,21 @@ public class KeycloakApplication extends Application {
|
|||
protected Set<Object> singletons = new HashSet<Object>();
|
||||
protected Set<Class<?>> classes = new HashSet<Class<?>>();
|
||||
|
||||
protected KeycloakSessionFactory factory;
|
||||
protected ProviderSessionFactory providerSessionFactory;
|
||||
protected String contextPath;
|
||||
|
||||
public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
|
||||
loadConfig();
|
||||
|
||||
this.providerSessionFactory = createProviderSessionFactory();
|
||||
|
||||
dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
|
||||
this.contextPath = context.getContextPath();
|
||||
this.factory = createSessionFactory();
|
||||
BruteForceProtector protector = new BruteForceProtector(factory);
|
||||
BruteForceProtector protector = new BruteForceProtector(providerSessionFactory);
|
||||
dispatcher.getDefaultContextObjects().put(BruteForceProtector.class, protector);
|
||||
ResteasyProviderFactory.pushContext(BruteForceProtector.class, protector); // for injection
|
||||
protector.start();
|
||||
context.setAttribute(BruteForceProtector.class.getName(), protector);
|
||||
this.providerSessionFactory = createProviderSessionFactory();
|
||||
context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
|
||||
|
||||
context.setAttribute(ProviderSessionFactory.class.getName(), this.providerSessionFactory);
|
||||
|
||||
TokenManager tokenManager = new TokenManager();
|
||||
|
@ -95,7 +86,7 @@ public class KeycloakApplication extends Application {
|
|||
|
||||
setupDefaultRealm(context.getContextPath());
|
||||
|
||||
setupScheduledTasks(providerSessionFactory, factory);
|
||||
setupScheduledTasks(providerSessionFactory);
|
||||
importRealms(context);
|
||||
|
||||
checkExportImportProvider();
|
||||
|
@ -115,55 +106,38 @@ public class KeycloakApplication extends Application {
|
|||
return uriInfo.getBaseUriBuilder().replacePath(getContextPath()).build();
|
||||
}
|
||||
|
||||
protected void loadConfig() {
|
||||
try {
|
||||
URL config = Thread.currentThread().getContextClassLoader().getResource("META-INF/keycloak-server.json");
|
||||
|
||||
if (config != null) {
|
||||
JsonNode node = new ObjectMapper().readTree(config);
|
||||
Config.init(new JsonConfigProvider(node));
|
||||
|
||||
log.info("Loaded config from " + config);
|
||||
return;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to load config", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupDefaultRealm(String contextPath) {
|
||||
new ApplianceBootstrap().bootstrap(factory, contextPath);
|
||||
}
|
||||
|
||||
|
||||
public static KeycloakSessionFactory createSessionFactory() {
|
||||
ModelProvider provider = ModelProviderUtils.getConfiguredModelProvider();
|
||||
|
||||
if (provider != null) {
|
||||
log.debug("Model provider: " + provider.getId());
|
||||
return provider.createFactory();
|
||||
}
|
||||
|
||||
throw new RuntimeException("Model provider not found");
|
||||
new ApplianceBootstrap().bootstrap(providerSessionFactory, contextPath);
|
||||
}
|
||||
|
||||
public static DefaultProviderSessionFactory createProviderSessionFactory() {
|
||||
DefaultProviderSessionFactory factory = new DefaultProviderSessionFactory();
|
||||
|
||||
factory.registerLoader(AuditProvider.class, ProviderFactoryLoader.create(AuditProviderFactory.class), Config.getAuditProvider());
|
||||
factory.registerLoader(AuditListener.class, ProviderFactoryLoader.create(AuditListenerFactory.class));
|
||||
factory.registerLoader(TimerProvider.class, ProviderFactoryLoader.create(TimerProviderFactory.class), Config.getTimerProvider());
|
||||
try {
|
||||
Class identityManagerProvider = Class.forName("org.keycloak.picketlink.IdentityManagerProvider");
|
||||
Class identityManagerProviderFactory = Class.forName("org.keycloak.picketlink.IdentityManagerProviderFactory");
|
||||
factory.registerLoader(identityManagerProvider, ProviderFactoryLoader.create(identityManagerProviderFactory), Config.getIdentityManagerProvider());
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.warn("Picketlink libraries not installed for IdentityManagerProviderFactory");
|
||||
}
|
||||
|
||||
factory.registerLoader(AuthenticationProvider.class, ProviderFactoryLoader.create(AuthenticationProviderFactory.class));
|
||||
factory.init();
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
public static void setupScheduledTasks(final ProviderSessionFactory providerSessionFactory, final KeycloakSessionFactory keycloakSessionFactory) {
|
||||
ProviderFactory<TimerProvider> timerFactory = providerSessionFactory.getProviderFactory(TimerProvider.class);
|
||||
if (timerFactory == null) {
|
||||
log.error("Can't setup schedule tasks, no timer provider found");
|
||||
return;
|
||||
}
|
||||
TimerProvider timer = timerFactory.create(null);
|
||||
timer.schedule(new ScheduledTaskRunner(keycloakSessionFactory, providerSessionFactory, new ClearExpiredAuditEvents()), Config.getAuditExpirationSchedule());
|
||||
timer.schedule(new ScheduledTaskRunner(keycloakSessionFactory, providerSessionFactory, new ClearExpiredUserSessions()), Config.getUserExpirationSchedule());
|
||||
}
|
||||
public static void setupScheduledTasks(final ProviderSessionFactory providerSessionFactory) {
|
||||
long interval = Config.scope("scheduled").getLong("interval") * 1000;
|
||||
|
||||
public KeycloakSessionFactory getFactory() {
|
||||
return factory;
|
||||
TimerProvider timer = providerSessionFactory.createSession().getProvider(TimerProvider.class);
|
||||
timer.schedule(new ScheduledTaskRunner(providerSessionFactory, new ClearExpiredAuditEvents()), interval);
|
||||
timer.schedule(new ScheduledTaskRunner(providerSessionFactory, new ClearExpiredUserSessions()), interval);
|
||||
}
|
||||
|
||||
public ProviderSessionFactory getProviderSessionFactory() {
|
||||
|
@ -215,7 +189,8 @@ public class KeycloakApplication extends Application {
|
|||
}
|
||||
|
||||
public void importRealm(RealmRepresentation rep, String from) {
|
||||
KeycloakSession session = factory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
try {
|
||||
session.getTransaction().begin();
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
@ -238,7 +213,7 @@ public class KeycloakApplication extends Application {
|
|||
|
||||
session.getTransaction().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,7 +230,7 @@ public class KeycloakApplication extends Application {
|
|||
|
||||
if (providers.hasNext()) {
|
||||
ExportImportProvider exportImport = providers.next();
|
||||
exportImport.checkExportImport(factory);
|
||||
exportImport.checkExportImport(providerSessionFactory);
|
||||
} else {
|
||||
log.warn("No ExportImportProvider found!");
|
||||
}
|
||||
|
|
|
@ -10,14 +10,12 @@ import org.keycloak.freemarker.Theme;
|
|||
import org.keycloak.freemarker.ThemeLoader;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.managers.AppAuthManager;
|
||||
import org.keycloak.services.managers.ApplicationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
@ -280,12 +278,7 @@ public class AdminConsole {
|
|||
|
||||
try {
|
||||
//logger.info("getting resource: " + path + " uri: " + uriInfo.getRequestUri().toString());
|
||||
String themeName = realm.getAdminTheme();
|
||||
if (themeName == null || themeName.trim().equals("")) {
|
||||
themeName = Config.getThemeAdmin();
|
||||
}
|
||||
|
||||
Theme theme = ThemeLoader.createTheme(themeName, Theme.Type.ADMIN);
|
||||
Theme theme = ThemeLoader.createTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
|
||||
InputStream resource = theme.getResourceAsStream(path);
|
||||
if (resource != null) {
|
||||
String contentType = mimeTypes.getContentType(path);
|
||||
|
|
|
@ -13,20 +13,18 @@ public class ScheduledTaskRunner implements Runnable {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(ScheduledTaskRunner.class);
|
||||
|
||||
private final KeycloakSessionFactory keycloakSessionFactory;
|
||||
private final ProviderSessionFactory providerSessionFactory;
|
||||
private final ScheduledTask task;
|
||||
|
||||
public ScheduledTaskRunner(KeycloakSessionFactory keycloakSessionFactory, ProviderSessionFactory providerSessionFactory, ScheduledTask task) {
|
||||
this.keycloakSessionFactory = keycloakSessionFactory;
|
||||
public ScheduledTaskRunner(ProviderSessionFactory providerSessionFactory, ScheduledTask task) {
|
||||
this.providerSessionFactory = providerSessionFactory;
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
KeycloakSession keycloakSession = keycloakSessionFactory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession keycloakSession = providerSession.getProvider(KeycloakSession.class);
|
||||
try {
|
||||
keycloakSession.getTransaction().begin();
|
||||
task.run(keycloakSession, providerSession);
|
||||
|
@ -38,11 +36,6 @@ public class ScheduledTaskRunner implements Runnable {
|
|||
|
||||
keycloakSession.getTransaction().rollback();
|
||||
} finally {
|
||||
try {
|
||||
keycloakSession.close();
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to close KeycloakSession", t);
|
||||
}
|
||||
try {
|
||||
providerSession.close();
|
||||
} catch (Throwable t) {
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
package org.keycloak.services.util;
|
||||
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.util.StringPropertyReplacer;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class JsonConfigProvider implements Config.ConfigProvider {
|
||||
|
||||
private JsonNode config;
|
||||
|
||||
public JsonConfigProvider(JsonNode config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProvider(String spi) {
|
||||
JsonNode n = getNode(spi, "provider");
|
||||
return n != null ? StringPropertyReplacer.replaceProperties(n.getTextValue()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config.Scope scope(String... path) {
|
||||
return new JsonScope(getNode(path));
|
||||
}
|
||||
|
||||
private JsonNode getNode(String... path) {
|
||||
JsonNode n = config;
|
||||
for (String p : path) {
|
||||
n = n.get(p);
|
||||
if (n == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public class JsonScope implements Config.Scope {
|
||||
|
||||
private JsonNode config;
|
||||
|
||||
public JsonScope(JsonNode config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key, String defaultValue) {
|
||||
if (config == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
JsonNode n = config.get(key);
|
||||
if (n == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return StringPropertyReplacer.replaceProperties(n.getTextValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(String key) {
|
||||
return getInt(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(String key, Integer defaultValue) {
|
||||
if (config == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
JsonNode n = config.get(key);
|
||||
if (n == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (n.isTextual()) {
|
||||
return Integer.parseInt(StringPropertyReplacer.replaceProperties(n.getTextValue()));
|
||||
} else {
|
||||
return n.getIntValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key) {
|
||||
return getLong(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key, Long defaultValue) {
|
||||
if (config == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
JsonNode n = config.get(key);
|
||||
if (n == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (n.isTextual()) {
|
||||
return Long.parseLong(StringPropertyReplacer.replaceProperties(n.getTextValue()));
|
||||
} else {
|
||||
return n.getLongValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key) {
|
||||
return getBoolean(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||
if (config == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
JsonNode n = config.get(key);
|
||||
if (n == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (n.isTextual()) {
|
||||
return Boolean.parseBoolean(StringPropertyReplacer.replaceProperties(n.getTextValue()));
|
||||
} else {
|
||||
return n.getBooleanValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,8 +2,6 @@ package org.keycloak.social;
|
|||
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
|
|
|
@ -90,10 +90,9 @@ public class SimpleHttpTest {
|
|||
|
||||
@Test
|
||||
public void testGetCustomHeader() throws IOException {
|
||||
JsonNode o = SimpleHttp.doGet("http://localhost:8081/tojson").header("Accept", "application/json").header("Authorization", "bearer dsfsadfsdf").asJson();
|
||||
JsonNode o = SimpleHttp.doGet("http://localhost:8081/tojson").header("Authorization", "bearer dsfsadfsdf").asJson();
|
||||
JsonNode h = o.get("headers");
|
||||
|
||||
assertEquals("application/json", h.get("Accept"));
|
||||
assertEquals("bearer dsfsadfsdf", h.get("Authorization").getTextValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ To run the tests with Firefox add `-Dbrowser=firefox` or for Chrome add `-Dbrows
|
|||
Mongo
|
||||
-----
|
||||
|
||||
The testsuite is executed with JPA model implementation with data saved in H2 database by default. To run testsuite with Mongo model, just add property `-Dkeycloak.model=mongo` when executing it.
|
||||
The testsuite is executed with JPA model implementation with data saved in H2 database by default. To run testsuite with Mongo model, just add property `-Dkeycloak.model.provider=mongo` when executing it.
|
||||
|
||||
Note that this will automatically run embedded Mongo database on localhost/27018 and it will stop it after whole testsuite is finished.
|
||||
So you don't need to have Mongo installed on your laptop to run mongo execution tests.
|
||||
|
@ -52,11 +52,11 @@ For example to use the example themes run the server with:
|
|||
|
||||
To start a Keycloak server with identity model data persisted in Mongo database instead of default JPA/H2 you can run:
|
||||
|
||||
mvn exec:java -Pkeycloak-server -Dkeycloak.model=mongo
|
||||
mvn exec:java -Pkeycloak-server -Dkeycloak.model.provider=mongo
|
||||
|
||||
By default it's using database `keycloak` on localhost/27017 and it uses already existing data from this DB (no cleanup of existing data during bootstrap). Assumption is that you already have DB running on localhost/27017 . Use system properties to configure things differently:
|
||||
|
||||
mvn exec:java -Pkeycloak-server -Dkeycloak.model=mongo -Dkeycloak.mongo.host=localhost -Dkeycloak.mongo.port=27017 -Dkeycloak.mongo.db=keycloak -Dkeycloak.mongo.clearCollectionsOnStartup=false
|
||||
mvn exec:java -Pkeycloak-server -Dkeycloak.model.provider=mongo -Dkeycloak.model.mongo.host=localhost -Dkeycloak.model.mongo.port=27017 -Dkeycloak.model.mongo.db=keycloak -Dkeycloak.model.mongo.clearOnStartup=false
|
||||
|
||||
TOTP codes
|
||||
----------
|
||||
|
|
|
@ -430,10 +430,10 @@
|
|||
</activation>
|
||||
|
||||
<properties>
|
||||
<keycloak.mongo.host>localhost</keycloak.mongo.host>
|
||||
<keycloak.mongo.port>27018</keycloak.mongo.port>
|
||||
<keycloak.mongo.db>keycloak</keycloak.mongo.db>
|
||||
<keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
@ -452,16 +452,17 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
|
||||
<keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
|
||||
<keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
|
||||
<keycloak.model.provider>mongo</keycloak.model.provider>
|
||||
<keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
|
||||
|
||||
<keycloak.audit>mongo</keycloak.audit>
|
||||
<keycloak.audit.mongo.host>${keycloak.mongo.host}</keycloak.audit.mongo.host>
|
||||
<keycloak.audit.mongo.port>${keycloak.mongo.port}</keycloak.audit.mongo.port>
|
||||
<keycloak.audit.mongo.db>${keycloak.mongo.db}</keycloak.audit.mongo.db>
|
||||
<keycloak.audit.provider>mongo</keycloak.audit.provider>
|
||||
<keycloak.audit.mongo.host>${keycloak.model.mongo.host}</keycloak.audit.mongo.host>
|
||||
<keycloak.audit.mongo.port>${keycloak.model.mongo.port}</keycloak.audit.mongo.port>
|
||||
<keycloak.audit.mongo.db>${keycloak.model.mongo.db}</keycloak.audit.mongo.db>
|
||||
|
||||
<keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -486,7 +487,7 @@
|
|||
<goal>start</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<port>${keycloak.mongo.port}</port>
|
||||
<port>${keycloak.model.mongo.port}</port>
|
||||
<logging>file</logging>
|
||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||
</configuration>
|
||||
|
|
|
@ -30,18 +30,16 @@ import io.undertow.servlet.api.FilterInfo;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.filters.ClientConnectionFilter;
|
||||
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.theme.DefaultKeycloakThemeProvider;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
@ -129,9 +127,8 @@ public class KeycloakServer {
|
|||
throw new RuntimeException("Invalid resources directory");
|
||||
}
|
||||
|
||||
if (Config.getThemeDir() == null) {
|
||||
System.setProperty(DefaultKeycloakThemeProvider.class.getName() + ".disabled", "");
|
||||
Config.setThemeDir(file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
||||
if (!System.getProperties().containsKey("keycloak.theme.dir")) {
|
||||
System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
||||
}
|
||||
|
||||
config.setResourcesHome(dir.getAbsolutePath());
|
||||
|
@ -162,8 +159,6 @@ public class KeycloakServer {
|
|||
|
||||
private KeycloakServerConfig config;
|
||||
|
||||
private KeycloakSessionFactory factory;
|
||||
|
||||
private ProviderSessionFactory providerSessionFactory;
|
||||
|
||||
private UndertowJaxrsServer server;
|
||||
|
@ -176,10 +171,6 @@ public class KeycloakServer {
|
|||
this.config = config;
|
||||
}
|
||||
|
||||
public KeycloakSessionFactory getKeycloakSessionFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
public ProviderSessionFactory getProviderSessionFactory() {
|
||||
return providerSessionFactory;
|
||||
}
|
||||
|
@ -194,7 +185,8 @@ public class KeycloakServer {
|
|||
}
|
||||
|
||||
public void importRealm(RealmRepresentation rep) {
|
||||
KeycloakSession session = factory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
|
||||
try {
|
||||
|
@ -217,12 +209,13 @@ public class KeycloakServer {
|
|||
|
||||
session.getTransaction().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupDevConfig() {
|
||||
KeycloakSession session = factory.createSession();
|
||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
|
||||
try {
|
||||
|
@ -234,7 +227,7 @@ public class KeycloakServer {
|
|||
|
||||
session.getTransaction().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,7 +259,6 @@ public class KeycloakServer {
|
|||
|
||||
server.deploy(di);
|
||||
|
||||
factory = ((KeycloakApplication) deployment.getApplication()).getFactory();
|
||||
providerSessionFactory = ((KeycloakApplication) deployment.getApplication()).getProviderSessionFactory();
|
||||
|
||||
setupDevConfig();
|
||||
|
@ -289,7 +281,6 @@ public class KeycloakServer {
|
|||
|
||||
public void stop() {
|
||||
providerSessionFactory.close();
|
||||
factory.close();
|
||||
server.stop();
|
||||
|
||||
info("Stopped Keycloak");
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"admin": {
|
||||
"realm": "keycloak-admin"
|
||||
},
|
||||
|
||||
"audit": {
|
||||
"provider": "${keycloak.audit.provider:jpa}"
|
||||
},
|
||||
|
||||
"model": {
|
||||
"provider": "${keycloak.model.provider:jpa}"
|
||||
},
|
||||
|
||||
"timer": {
|
||||
"provider": "basic"
|
||||
},
|
||||
|
||||
"theme": {
|
||||
"default": "keycloak",
|
||||
"dir": "${keycloak.theme.dir}"
|
||||
},
|
||||
|
||||
"scheduled": {
|
||||
"interval": 900
|
||||
}
|
||||
}
|
|
@ -4,10 +4,10 @@ import org.hamcrest.CoreMatchers;
|
|||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.AuditListenerFactory;
|
||||
import org.keycloak.audit.Details;
|
||||
|
@ -58,11 +58,6 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
|
|||
return "assert-events";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement apply(final Statement base, org.junit.runner.Description description) {
|
||||
return new Statement() {
|
||||
|
@ -194,7 +189,7 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,18 +22,14 @@
|
|||
package org.keycloak.testsuite.account;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.audit.Details;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.jpa.JpaAuditProviderFactory;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.adapters.action.SessionStats;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -171,11 +172,11 @@ public class AdapterTest {
|
|||
System.out.println(pageSource);
|
||||
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
|
||||
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.getRealmByName("demo");
|
||||
ProviderSession providerSession = keycloakRule.startSession();
|
||||
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||
int originalIdle = realm.getSsoSessionIdleTimeout();
|
||||
realm.setSsoSessionIdleTimeout(1);
|
||||
keycloakRule.stopSession(session, true);
|
||||
keycloakRule.stopSession(providerSession, true);
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
|
@ -184,10 +185,10 @@ public class AdapterTest {
|
|||
driver.navigate().to("http://localhost:8081/product-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("demo");
|
||||
providerSession = keycloakRule.startSession();
|
||||
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||
realm.setSsoSessionIdleTimeout(originalIdle);
|
||||
keycloakRule.stopSession(session, true);
|
||||
keycloakRule.stopSession(providerSession, true);
|
||||
}
|
||||
@Test
|
||||
public void testLoginSSOMax() throws Exception {
|
||||
|
@ -202,11 +203,11 @@ public class AdapterTest {
|
|||
System.out.println(pageSource);
|
||||
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
|
||||
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.getRealmByName("demo");
|
||||
ProviderSession providerSession = keycloakRule.startSession();
|
||||
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||
int original = realm.getSsoSessionMaxLifespan();
|
||||
realm.setSsoSessionMaxLifespan(1);
|
||||
keycloakRule.stopSession(session, true);
|
||||
keycloakRule.stopSession(providerSession, true);
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
|
@ -215,9 +216,9 @@ public class AdapterTest {
|
|||
driver.navigate().to("http://localhost:8081/product-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("demo");
|
||||
providerSession = keycloakRule.startSession();
|
||||
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||
realm.setSsoSessionMaxLifespan(original);
|
||||
keycloakRule.stopSession(session, true);
|
||||
keycloakRule.stopSession(providerSession, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,14 +29,12 @@ import org.keycloak.OAuth2Constants;
|
|||
import org.keycloak.audit.Details;
|
||||
import org.keycloak.audit.Errors;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.RefreshToken;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||
|
@ -47,7 +45,11 @@ import org.keycloak.testsuite.rule.WebRule;
|
|||
import org.keycloak.util.Time;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
|
@ -181,8 +183,8 @@ public class RefreshTokenTest {
|
|||
|
||||
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
|
||||
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.getRealmByName("test");
|
||||
ProviderSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
UserSessionModel userSession = realm.getUserSession(sessionId);
|
||||
int last = userSession.getLastSessionRefresh();
|
||||
keycloakRule.stopSession(session, false);
|
||||
|
@ -197,7 +199,7 @@ public class RefreshTokenTest {
|
|||
Assert.assertEquals(200, tokenResponse.getStatusCode());
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("test");
|
||||
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
userSession = realm.getUserSession(sessionId);
|
||||
int next = userSession.getLastSessionRefresh();
|
||||
keycloakRule.stopSession(session, false);
|
||||
|
@ -208,7 +210,7 @@ public class RefreshTokenTest {
|
|||
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("test");
|
||||
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
int lastAccessTokenLifespan = realm.getAccessTokenLifespan();
|
||||
realm.setAccessTokenLifespan(100000);
|
||||
keycloakRule.stopSession(session, true);
|
||||
|
@ -217,7 +219,7 @@ public class RefreshTokenTest {
|
|||
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("test");
|
||||
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
userSession = realm.getUserSession(sessionId);
|
||||
next = userSession.getLastSessionRefresh();
|
||||
keycloakRule.stopSession(session, false);
|
||||
|
@ -226,7 +228,7 @@ public class RefreshTokenTest {
|
|||
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 6)));
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("test");
|
||||
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
int originalIdle = realm.getSsoSessionIdleTimeout();
|
||||
realm.setSsoSessionIdleTimeout(1);
|
||||
keycloakRule.stopSession(session, true);
|
||||
|
@ -243,7 +245,7 @@ public class RefreshTokenTest {
|
|||
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("test");
|
||||
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
realm.setSsoSessionIdleTimeout(originalIdle);
|
||||
realm.setAccessTokenLifespan(lastAccessTokenLifespan);
|
||||
keycloakRule.stopSession(session, true);
|
||||
|
@ -266,8 +268,8 @@ public class RefreshTokenTest {
|
|||
|
||||
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
|
||||
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.getRealmByName("test");
|
||||
ProviderSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
int maxLifespan = realm.getSsoSessionMaxLifespan();
|
||||
realm.setSsoSessionMaxLifespan(1);
|
||||
keycloakRule.stopSession(session, true);
|
||||
|
@ -281,7 +283,7 @@ public class RefreshTokenTest {
|
|||
assertNull(tokenResponse.getRefreshToken());
|
||||
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.getRealmByName("test");
|
||||
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||
realm.setSsoSessionMaxLifespan(maxLifespan);
|
||||
keycloakRule.stopSession(session, true);
|
||||
|
||||
|
|
|
@ -6,10 +6,11 @@ import io.undertow.servlet.api.SecurityConstraint;
|
|||
import io.undertow.servlet.api.ServletInfo;
|
||||
import io.undertow.servlet.api.WebResourceCollection;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
|
@ -33,31 +34,33 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
|||
server = new KeycloakServer();
|
||||
server.start();
|
||||
|
||||
|
||||
setupKeycloak();
|
||||
}
|
||||
|
||||
public UserRepresentation getUser(String realm, String name) {
|
||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
try {
|
||||
UserModel user = session.getRealmByName(realm).getUser(name);
|
||||
return user != null ? ModelToRepresentation.toRepresentation(user) : null;
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
public UserRepresentation getUserById(String realm, String id) {
|
||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
try {
|
||||
return ModelToRepresentation.toRepresentation(session.getRealmByName(realm).getUserById(id));
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupKeycloak() {
|
||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
|
||||
try {
|
||||
|
@ -69,9 +72,8 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
|||
|
||||
session.getTransaction().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
providerSession.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void configure(RealmManager manager, RealmModel adminRealm) {
|
||||
|
@ -134,15 +136,16 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
|||
return JsonSerialization.readValue(bytes, RealmRepresentation.class);
|
||||
}
|
||||
|
||||
public KeycloakSession startSession() {
|
||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||
public ProviderSession startSession() {
|
||||
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
return session;
|
||||
return providerSession;
|
||||
}
|
||||
|
||||
public void stopSession(KeycloakSession session, boolean commit) {
|
||||
public void stopSession(ProviderSession session, boolean commit) {
|
||||
if (commit) {
|
||||
session.getTransaction().commit();
|
||||
session.getProvider(KeycloakSession.class).getTransaction().commit();
|
||||
}
|
||||
session.close();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.rule;
|
||||
|
||||
import org.keycloak.models.Config;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
|
@ -61,8 +61,8 @@ public class KeycloakRule extends AbstractKeycloakRule {
|
|||
}
|
||||
|
||||
public void configure(KeycloakSetup configurer) {
|
||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
||||
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||
session.getTransaction().begin();
|
||||
|
||||
try {
|
||||
|
@ -77,17 +77,16 @@ public class KeycloakRule extends AbstractKeycloakRule {
|
|||
session.getTransaction().commit();
|
||||
} finally {
|
||||
providerSession.close();
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUserSession(String sessionId) {
|
||||
KeycloakSession keycloakSession = startSession();
|
||||
RealmModel realm = keycloakSession.getRealm("test");
|
||||
ProviderSession providerSession = startSession();
|
||||
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealm("test");
|
||||
UserSessionModel session = realm.getUserSession(sessionId);
|
||||
assertNotNull(session);
|
||||
realm.removeUserSession(session);
|
||||
stopSession(keycloakSession, true);
|
||||
stopSession(providerSession, true);
|
||||
}
|
||||
|
||||
public abstract static class KeycloakSetup {
|
||||
|
|
|
@ -6,6 +6,8 @@ import org.apache.jmeter.samplers.SampleResult;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.provider.ProviderSessionFactory;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
@ -18,17 +20,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||
|
||||
|
||||
private static FutureTask<KeycloakSessionFactory> factoryProvider = new FutureTask<KeycloakSessionFactory>(new Callable() {
|
||||
private static FutureTask<ProviderSessionFactory> factoryProvider = new FutureTask<ProviderSessionFactory>(new Callable() {
|
||||
|
||||
@Override
|
||||
public KeycloakSessionFactory call() throws Exception {
|
||||
return KeycloakApplication.createSessionFactory();
|
||||
public ProviderSessionFactory call() throws Exception {
|
||||
return KeycloakApplication.createProviderSessionFactory();
|
||||
}
|
||||
|
||||
});
|
||||
private static AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
private KeycloakSessionFactory factory;
|
||||
private ProviderSessionFactory factory;
|
||||
// private KeycloakSession identitySession;
|
||||
private Worker worker;
|
||||
private boolean setupSuccess = false;
|
||||
|
@ -42,7 +44,8 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
|||
worker = getWorker();
|
||||
|
||||
factory = getFactory();
|
||||
KeycloakSession identitySession = factory.createSession();
|
||||
ProviderSession providerSession = factory.createSession();
|
||||
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
KeycloakTransaction transaction = identitySession.getTransaction();
|
||||
transaction.begin();
|
||||
|
||||
|
@ -56,11 +59,11 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
|||
} else {
|
||||
transaction.rollback();
|
||||
}
|
||||
identitySession.close();
|
||||
providerSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static KeycloakSessionFactory getFactory() {
|
||||
private static ProviderSessionFactory getFactory() {
|
||||
factoryProvider.run();
|
||||
try {
|
||||
return factoryProvider.get();
|
||||
|
@ -98,7 +101,8 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
|||
return result;
|
||||
}
|
||||
|
||||
KeycloakSession identitySession = factory.createSession();
|
||||
ProviderSession providerSession = factory.createSession();
|
||||
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||
KeycloakTransaction transaction = identitySession.getTransaction();
|
||||
try {
|
||||
transaction.begin();
|
||||
|
@ -114,7 +118,7 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
|||
} finally {
|
||||
result.sampleEnd();
|
||||
result.setSuccessful(true);
|
||||
identitySession.close();
|
||||
providerSession.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -8,11 +8,11 @@ keycloak.jpa.hbm2ddl.auto=create
|
|||
|
||||
|
||||
## Configure MongoDB (Useful just when keycloak.sessionFactory=mongo)
|
||||
keycloak.mongodb.host=localhost
|
||||
keycloak.mongodb.port=27017
|
||||
keycloak.mongodb.databaseName=keycloakPerfTest
|
||||
keycloak.model.mongo.host=localhost
|
||||
keycloak.model.mongo.port=27017
|
||||
keycloak.model.mongo.databaseName=keycloakPerfTest
|
||||
# Should be DB dropped at startup of the test?
|
||||
keycloak.mongodb.dropDatabaseOnStartup=true
|
||||
keycloak.model.mongo.dropDatabaseOnStartup=true
|
||||
|
||||
|
||||
## Specify Keycloak worker class
|
||||
|
|
|
@ -7,6 +7,6 @@ import org.keycloak.provider.Provider;
|
|||
*/
|
||||
public interface TimerProvider extends Provider {
|
||||
|
||||
public void schedule(Runnable runnable, String config);
|
||||
public void schedule(Runnable runnable, long interval);
|
||||
|
||||
}
|
||||
|
|
25
timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
Normal file
25
timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package org.keycloak.timer;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class TimerSpi implements Spi {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "timer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return TimerProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return TimerProviderFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.timer.TimerSpi
|
|
@ -18,9 +18,7 @@ public class BasicTimerProvider implements TimerProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void schedule(final Runnable runnable, String config) {
|
||||
long interval = Long.parseLong(config);
|
||||
|
||||
public void schedule(final Runnable runnable, final long interval) {
|
||||
TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.timer.basic;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.timer.TimerProvider;
|
||||
import org.keycloak.timer.TimerProviderFactory;
|
||||
|
@ -19,7 +20,7 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
public void init(Config.Scope config) {
|
||||
timer = new Timer();
|
||||
}
|
||||
|
||||
|
@ -34,8 +35,4 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
|
|||
return "basic";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazyLoad() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue