diff --git a/audit/api/src/main/java/org/keycloak/audit/Audit.java b/audit/api/src/main/java/org/keycloak/audit/Audit.java
index 1ccdca830a..625074f733 100644
--- a/audit/api/src/main/java/org/keycloak/audit/Audit.java
+++ b/audit/api/src/main/java/org/keycloak/audit/Audit.java
@@ -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;
/**
diff --git a/audit/api/src/main/java/org/keycloak/audit/AuditListenerSpi.java b/audit/api/src/main/java/org/keycloak/audit/AuditListenerSpi.java
new file mode 100644
index 0000000000..e2f0b9cf46
--- /dev/null
+++ b/audit/api/src/main/java/org/keycloak/audit/AuditListenerSpi.java
@@ -0,0 +1,27 @@
+package org.keycloak.audit;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Stian Thorgersen
+ */
+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;
+ }
+
+}
diff --git a/audit/api/src/main/java/org/keycloak/audit/AuditProviderSpi.java b/audit/api/src/main/java/org/keycloak/audit/AuditProviderSpi.java
new file mode 100644
index 0000000000..249f7eab01
--- /dev/null
+++ b/audit/api/src/main/java/org/keycloak/audit/AuditProviderSpi.java
@@ -0,0 +1,27 @@
+package org.keycloak.audit;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Stian Thorgersen
+ */
+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;
+ }
+
+}
diff --git a/audit/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/audit/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000000..2a1aeb8ea4
--- /dev/null
+++ b/audit/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,2 @@
+org.keycloak.audit.AuditProviderSpi
+org.keycloak.audit.AuditListenerSpi
\ No newline at end of file
diff --git a/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java b/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java
index 1f936afce4..1bafa9f3af 100644
--- a/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java
+++ b/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java
@@ -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 Stian Thorgersen
@@ -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;
- }
-
}
diff --git a/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java b/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java
index c7d7a1a96f..01f72e26fb 100644
--- a/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java
+++ b/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java
@@ -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;
- }
-
}
diff --git a/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java b/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java
index 8f78fb4371..4ffcda1b16 100644
--- a/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java
+++ b/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java
@@ -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 Stian Thorgersen
@@ -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;
- }
-
}
diff --git a/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java b/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java
index 3de7473a82..b24ee37a09 100644
--- a/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java
+++ b/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java
@@ -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 Stian Thorgersen
@@ -23,9 +24,14 @@ public abstract class AbstractAuditProviderTest {
@Before
public void before() {
- ProviderFactoryLoader loader = ProviderFactoryLoader.create(AuditProviderFactory.class);
- factory = loader.find(getProviderId());
- factory.init();
+ String providerId = getProviderId();
+ ServiceLoader 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);
}
diff --git a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationSpi.java b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationSpi.java
new file mode 100644
index 0000000000..875b150ca9
--- /dev/null
+++ b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationSpi.java
@@ -0,0 +1,27 @@
+package org.keycloak.authentication;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Stian Thorgersen
+ */
+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;
+ }
+
+}
diff --git a/authentication/authentication-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/authentication/authentication-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000000..9305401896
--- /dev/null
+++ b/authentication/authentication-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1 @@
+org.keycloak.authentication.AuthenticationSpi
\ No newline at end of file
diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java
index 3f58d4e33d..4a208c0928 100644
--- a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java
+++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java
@@ -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 Marek Posolda
@@ -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;
- }
}
diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java
index 8b9e6c1666..47ef6375e9 100644
--- a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java
+++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java
@@ -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;
- }
}
diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java
index 0027be6fdd..ce69bd3062 100755
--- a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java
+++ b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java
@@ -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
*
diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java
index db1ece3e0f..29cdb6fd86 100644
--- a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java
+++ b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java
@@ -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;
- }
}
diff --git a/core/src/main/java/org/keycloak/Config.java b/core/src/main/java/org/keycloak/Config.java
new file mode 100644
index 0000000000..34d0fa4518
--- /dev/null
+++ b/core/src/main/java/org/keycloak/Config.java
@@ -0,0 +1,129 @@
+package org.keycloak;
+
+/**
+ * @author Stian Thorgersen
+ */
+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 Stian Thorgersen
+ */
+ 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);
+
+ }
+}
diff --git a/core/src/main/java/org/keycloak/provider/ProviderFactory.java b/core/src/main/java/org/keycloak/provider/ProviderFactory.java
index 996d2c5356..0e49732268 100644
--- a/core/src/main/java/org/keycloak/provider/ProviderFactory.java
+++ b/core/src/main/java/org/keycloak/provider/ProviderFactory.java
@@ -1,5 +1,7 @@
package org.keycloak.provider;
+import org.keycloak.Config;
+
/**
* @author Stian Thorgersen
*/
@@ -7,12 +9,10 @@ public interface ProviderFactory {
public T create(ProviderSession providerSession);
- public void init();
+ public void init(Config.Scope config);
public void close();
public String getId();
- public boolean lazyLoad();
-
}
diff --git a/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java b/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java
deleted file mode 100644
index 8c3f62a262..0000000000
--- a/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java
+++ /dev/null
@@ -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 Stian Thorgersen
- */
-public class ProviderFactoryLoader implements Iterable> {
-
- private final Map> factories = new HashMap>();
-
- 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> iterator() {
- return factories.values().iterator();
- }
-
- public Set 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 implements ProviderFactory {
-
- private final ProviderFactory factory;
-
- private volatile boolean initialized = false;
-
- private LazyProviderFactory(ProviderFactory 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;
- }
- }
-
-}
diff --git a/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java b/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java
index 2e347dfc15..93536d0a29 100755
--- a/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java
+++ b/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java
@@ -1,7 +1,5 @@
package org.keycloak.provider;
-import java.util.Set;
-
/**
* @author Stian Thorgersen
*/
@@ -11,12 +9,6 @@ public interface ProviderSessionFactory {
void close();
- ProviderFactory getProviderFactory(Class clazz);
-
- ProviderFactory getProviderFactory(Class clazz, String id);
-
- Set providerIds(Class extends Provider> clazz);
-
void init();
}
diff --git a/core/src/main/java/org/keycloak/provider/Spi.java b/core/src/main/java/org/keycloak/provider/Spi.java
new file mode 100644
index 0000000000..03b9afcc24
--- /dev/null
+++ b/core/src/main/java/org/keycloak/provider/Spi.java
@@ -0,0 +1,12 @@
+package org.keycloak.provider;
+
+/**
+ * @author Stian Thorgersen
+ */
+public interface Spi {
+
+ public String getName();
+ public Class extends Provider> getProviderClass();
+ public Class extends ProviderFactory> getProviderFactoryClass();
+
+}
diff --git a/core/src/main/java/org/keycloak/util/CollectionUtil.java b/core/src/main/java/org/keycloak/util/CollectionUtil.java
new file mode 100644
index 0000000000..41df40e698
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/CollectionUtil.java
@@ -0,0 +1,26 @@
+package org.keycloak.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * @author Jeroen Rosenberg
+ */
+public class CollectionUtil {
+
+ public static String join(Collection strings) {
+ return join(strings, ", ");
+ }
+
+ public static String join(Collection strings, String separator) {
+ Iterator iter = strings.iterator();
+ StringBuilder sb = new StringBuilder();
+ if(iter.hasNext()){
+ sb.append(iter.next());
+ while(iter.hasNext()){
+ sb.append(separator).append(iter.next());
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/core/src/main/java/org/keycloak/util/StringPropertyReplacer.java b/core/src/main/java/org/keycloak/util/StringPropertyReplacer.java
new file mode 100644
index 0000000000..d46f69900f
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/StringPropertyReplacer.java
@@ -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 Jason Dillon
+ * @author Scott Stark
+ * @author Claudio Vesco
+ * @author Adrian Brock
+ * @author Dimitris Andreadis
+ * @version $Revision: 2898 $
+ */
+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;
+ }
+}
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml
index 873fd6eb8f..70f14f4f23 100755
--- a/docbook/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/reference/en/en-US/modules/server-installation.xml
@@ -252,12 +252,12 @@ keycloak-war-dist-all-1.0-beta-1-SNAPSHOT/
First you need to specify that you want to use mongo instead of default jpa model, and you may also specify
host, port and name of mongo database. So you can start keycloak with the command like this:
Note that when you install MongoDB on your laptop, it's usually on localhost/270717 by default. That's why properties
- keycloak.mongo.host and keycloak.mongo.port are not mandatory, but they already have
- default values localhost and 27017 . Similarly property keycloak.mongo.db
+ keycloak.model.mongo.host and keycloak.model.mongo.port are not mandatory, but they already have
+ default values localhost and 27017 . Similarly property keycloak.model.mongo.db
has default value keycloak for name of underlying database. So the example above could be simplified like:
+
+ org.keycloak
+ keycloak-core
+ ${project.version}
+ provided
+
org.keycloak
keycloak-model-api
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java
index 9ada46bfca..97983706af 100644
--- a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java
@@ -1,11 +1,12 @@
package org.keycloak.exportimport;
-import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderSessionFactory;
/**
* @author Marek Posolda
*/
public interface ExportImportProvider {
- void checkExportImport(KeycloakSessionFactory identitySessionFactory);
+ void checkExportImport(ProviderSessionFactory identitySessionFactory);
+
}
diff --git a/export-import/export-import-impl/pom.xml b/export-import/export-import-impl/pom.xml
index a4898e50a9..17a566ee7f 100644
--- a/export-import/export-import-impl/pom.xml
+++ b/export-import/export-import-impl/pom.xml
@@ -32,13 +32,6 @@
${project.version}
provided
-
- org.keycloak
- keycloak-audit-api
- ${project.version}
- provided
-
-
org.jboss.resteasy
jaxrs-api
@@ -121,6 +114,12 @@
${project.version}
test
+
+ org.keycloak
+ keycloak-model-tests
+ ${project.version}
+ test
+
org.hibernate.javax.persistence
hibernate-jpa-2.0-api
@@ -149,10 +148,10 @@
- localhost
- 27018
- keycloak
- true
+ localhost
+ 27018
+ keycloak
+ true
@@ -179,10 +178,10 @@
- ${keycloak.mongo.host}
- ${keycloak.mongo.port}
- ${keycloak.mongo.db}
- ${keycloak.mongo.clearOnStartup}
+ ${keycloak.model.mongo.host}
+ ${keycloak.model.mongo.port}
+ ${keycloak.model.mongo.db}
+ ${keycloak.model.mongo.clearOnStartup}
@@ -207,7 +206,7 @@
start
- ${keycloak.mongo.port}
+ ${keycloak.model.mongo.port}
file
${project.build.directory}/mongodb.log
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportConfig.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportConfig.java
new file mode 100644
index 0000000000..d87b55cf32
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportConfig.java
@@ -0,0 +1,54 @@
+package org.keycloak.exportimport;
+
+/**
+ * @author Stian Thorgersen
+ */
+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);
+ }
+
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
index 32e0b84f74..de84633082 100644
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
@@ -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 providers = ProviderLoader.load(ExportImportIOProvider.class);
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
index 3bfc9aa788..15f9fae027 100755
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
@@ -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;
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java
index 962c3acef8..b785c4174a 100644
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java
@@ -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();
}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java
index 837157e5e6..31883acb14 100644
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java
@@ -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 Marek Posolda
@@ -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) {
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java
index 1e39f24323..49817c7e0a 100644
--- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java
@@ -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 Marek Posolda
*/
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() {
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
index 8175bdb498..52ee05476f 100644
--- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
@@ -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);
}
}
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
index e715c9c662..849c388a75 100644
--- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
@@ -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()) {
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeLoader.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeLoader.java
index c64bff6713..23f99e3567 100755
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeLoader.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeLoader.java
@@ -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 providers = new LinkedList();
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/DefaultKeycloakThemeProvider.java b/forms/common-themes/src/main/java/org/keycloak/theme/DefaultKeycloakThemeProvider.java
index a323945959..8a8659c4d2 100644
--- a/forms/common-themes/src/main/java/org/keycloak/theme/DefaultKeycloakThemeProvider.java
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/DefaultKeycloakThemeProvider.java
@@ -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;
/**
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java b/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
index a76b32813d..101851c9b7 100644
--- a/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
@@ -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);
}
diff --git a/model/api/src/main/java/org/keycloak/models/Config.java b/model/api/src/main/java/org/keycloak/models/Config.java
deleted file mode 100644
index f0416d1657..0000000000
--- a/model/api/src/main/java/org/keycloak/models/Config.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.keycloak.models;
-
-import java.io.File;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Stian Thorgersen
- */
-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);
- }
-
-}
diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
index 9aa55ee2d1..aa61bec51b 100755
--- a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -1,12 +1,14 @@
package org.keycloak.models;
+import org.keycloak.provider.Provider;
+
import java.util.List;
/**
* @author Bill Burke
* @version $Revision: 1 $
*/
-public interface KeycloakSession {
+public interface KeycloakSession extends Provider {
KeycloakTransaction getTransaction();
RealmModel createRealm(String name);
diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java b/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java
index 3149f9b27b..dba6d84291 100755
--- a/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java
+++ b/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java
@@ -1,10 +1,13 @@
package org.keycloak.models;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.ProviderSession;
+
/**
* @author Bill Burke
* @version $Revision: 1 $
*/
-public interface KeycloakSessionFactory {
- KeycloakSession createSession();
+public interface KeycloakSessionFactory extends ProviderFactory {
+ KeycloakSession create(ProviderSession providerSession);
void close();
}
diff --git a/model/api/src/main/java/org/keycloak/models/ModelSpi.java b/model/api/src/main/java/org/keycloak/models/ModelSpi.java
new file mode 100644
index 0000000000..42586e9ede
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/ModelSpi.java
@@ -0,0 +1,27 @@
+package org.keycloak.models;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Stian Thorgersen
+ */
+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;
+ }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelProviderUtils.java b/model/api/src/main/java/org/keycloak/models/utils/ModelProviderUtils.java
deleted file mode 100644
index 8ddedab298..0000000000
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelProviderUtils.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.keycloak.models.utils;
-
-import java.util.ServiceLoader;
-
-import org.keycloak.models.Config;
-import org.keycloak.models.ModelProvider;
-
-/**
- * @author Marek Posolda
- */
-public class ModelProviderUtils {
-
- public static final String DEFAULT_MODEL_PROVIDER = "jpa";
-
- public static Iterable getRegisteredProviders() {
- return ServiceLoader.load(ModelProvider.class);
- }
-
- public static ModelProvider getConfiguredModelProvider(Iterable 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());
- }
-
-}
diff --git a/model/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/model/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000000..48ff59e26d
--- /dev/null
+++ b/model/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1 @@
+org.keycloak.models.ModelSpi
\ No newline at end of file
diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index 15ac823ca5..c12e9cde06 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -30,24 +30,6 @@
${project.version}
provided
-
- org.keycloak
- keycloak-audit-api
- ${project.version}
- provided
-
-
- org.keycloak
- keycloak-audit-jpa
- ${project.version}
- provided
-
-
- org.keycloak
- keycloak-audit-jboss-logging
- ${project.version}
- provided
-
org.keycloak
keycloak-model-api
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
index 67ba543832..6efe710f92 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
@@ -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 Bill Burke
* @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;
+ }
+
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java
deleted file mode 100755
index f49e1f2e2e..0000000000
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java
+++ /dev/null
@@ -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 Bill Burke
- * @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;
- }
-}
diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.KeycloakSessionFactory b/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.KeycloakSessionFactory
new file mode 100644
index 0000000000..d77ce1b877
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.KeycloakSessionFactory
@@ -0,0 +1 @@
+org.keycloak.models.jpa.JpaKeycloakSessionFactory
\ No newline at end of file
diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider b/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider
deleted file mode 100644
index 199922e3f1..0000000000
--- a/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.models.jpa.JpaModelProvider
\ No newline at end of file
diff --git a/model/mongo/pom.xml b/model/mongo/pom.xml
index 01bce2f149..cab3668761 100755
--- a/model/mongo/pom.xml
+++ b/model/mongo/pom.xml
@@ -44,18 +44,6 @@
${project.version}
provided
-
- org.keycloak
- keycloak-audit-api
- ${project.version}
- provided
-
-
- org.keycloak
- keycloak-audit-jboss-logging
- ${project.version}
- provided
-
org.jboss.logging
jboss-logging
@@ -103,10 +91,10 @@
- localhost
- 27018
- keycloak
- true
+ localhost
+ 27018
+ keycloak
+ true
@@ -133,10 +121,10 @@
- ${keycloak.mongo.host}
- ${keycloak.mongo.port}
- ${keycloak.mongo.db}
- ${keycloak.mongo.clearOnStartup}
+ ${keycloak.model.mongo.host}
+ ${keycloak.model.mongo.port}
+ ${keycloak.model.mongo.db}
+ ${keycloak.model.mongo.clearOnStartup}
org.keycloak:keycloak-model-tests
@@ -164,7 +152,7 @@
start
- ${keycloak.mongo.port}
+ ${keycloak.model.mongo.port}
file
${project.build.directory}/mongodb.log
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java
deleted file mode 100755
index 45197c70d8..0000000000
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java
+++ /dev/null
@@ -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 Bill Burke
- * @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);
- }
-}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java
index 6feb373324..142cdbe356 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java
@@ -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
@@ -27,7 +35,7 @@ import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEnti
public class MongoKeycloakSessionFactory implements KeycloakSessionFactory {
protected static final Logger logger = Logger.getLogger(MongoKeycloakSessionFactory.class);
- private static final Class>[] MANAGED_ENTITY_TYPES = (Class>[])new Class>[] {
+ private static final Class>[] MANAGED_ENTITY_TYPES = (Class>[]) new Class>[]{
MongoRealmEntity.class,
MongoUserEntity.class,
MongoRoleEntity.class,
@@ -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();
}
+
}
+
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProvider.java
deleted file mode 100644
index 180f37dcdd..0000000000
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProvider.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.keycloak.models.mongo.keycloak.config;
-
-import com.mongodb.DB;
-import com.mongodb.MongoClient;
-
-/**
- * @author Marek Posolda
- */
-public interface MongoClientProvider {
-
- MongoClient getMongoClient();
-
- DB getDB();
-
- /**
- * @return true if collections should be cleared on startup
- */
- boolean clearCollectionsOnStartup();
-
- void close();
-}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java
deleted file mode 100644
index 038e805c4d..0000000000
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.keycloak.models.mongo.keycloak.config;
-
-/**
- * Provides {@link MongoClientProvider} instance
- *
- * @author Marek Posolda
- */
-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;
- }
-}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java
deleted file mode 100755
index 4635fd4a3c..0000000000
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java
+++ /dev/null
@@ -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 Marek Posolda
- */
-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);
- }
-}
diff --git a/model/mongo/src/main/resources/META-INF/services/org.keycloak.models.KeycloakSessionFactory b/model/mongo/src/main/resources/META-INF/services/org.keycloak.models.KeycloakSessionFactory
new file mode 100644
index 0000000000..47363dca90
--- /dev/null
+++ b/model/mongo/src/main/resources/META-INF/services/org.keycloak.models.KeycloakSessionFactory
@@ -0,0 +1 @@
+org.keycloak.models.mongo.keycloak.adapters.MongoKeycloakSessionFactory
\ No newline at end of file
diff --git a/model/mongo/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider b/model/mongo/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider
deleted file mode 100644
index c9e753986d..0000000000
--- a/model/mongo/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.models.mongo.keycloak.MongoModelProvider
\ No newline at end of file
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
deleted file mode 100755
index d549fa79c8..0000000000
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
+++ /dev/null
@@ -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 Marek Posolda
- */
-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;
- }
-}
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java
deleted file mode 100644
index 7e13e94896..0000000000
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java
+++ /dev/null
@@ -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 Marek Posolda
- */
-public class AddressWithFlats extends Address {
-
- private List flatNumbers;
-
- public List getFlatNumbers() {
- return flatNumbers;
- }
-
- public void setFlatNumbers(List flatNumbers) {
- this.flatNumbers = flatNumbers;
- }
-}
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java
deleted file mode 100755
index f48b372c58..0000000000
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java
+++ /dev/null
@@ -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 Marek Posolda
- */
-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 addresses = new ArrayList();
- 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 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 List asList(T... objects) {
- List list = new ArrayList();
- list.addAll(Arrays.asList(objects));
- return list;
- }
-}
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
deleted file mode 100755
index 3db661671c..0000000000
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
+++ /dev/null
@@ -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 Marek Posolda
- */
-@MongoCollection(collectionName = "persons")
-public class Person implements MongoIdentifiableEntity {
-
- private String id;
- private String firstName;
- private int age;
- private List kids;
- private List addresses;
- private Address mainAddress;
- private Gender gender;
- private List genders;
- private Map attributes = new HashMap();
-
- 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 getGenders() {
- return genders;
- }
-
- public void setGenders(List genders) {
- this.genders = genders;
- }
-
- public List getKids() {
- return kids;
- }
-
- public void setKids(List kids) {
- this.kids = kids;
- }
-
- public List getAddresses() {
- return addresses;
- }
-
- public void setAddresses(List addresses) {
- this.addresses = addresses;
- }
-
- public Address getMainAddress() {
- return mainAddress;
- }
-
- public void setMainAddress(Address mainAddress) {
- this.mainAddress = mainAddress;
- }
-
- public Map getAttributes() {
- return attributes;
- }
-
- public void setAttributes(Map 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
- }
-}
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java
index 2f7177b215..428d4c8bb1 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java
@@ -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);
}
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
index 880ce1462c..a603226fdb 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
@@ -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);
diff --git a/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerSpi.java b/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerSpi.java
new file mode 100644
index 0000000000..42111da0d3
--- /dev/null
+++ b/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerSpi.java
@@ -0,0 +1,25 @@
+package org.keycloak.picketlink;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Stian Thorgersen
+ */
+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;
+ }
+}
diff --git a/picketlink/keycloak-picketlink-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/picketlink/keycloak-picketlink-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000000..ffcb6e5424
--- /dev/null
+++ b/picketlink/keycloak-picketlink-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1 @@
+org.keycloak.picketlink.IdentityManagerSpi
\ No newline at end of file
diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java
index 83b5970816..236cff6726 100644
--- a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java
+++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java
@@ -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;
- }
}
diff --git a/project-integrations/aerogear-ups/auth-server/src/main/java/org/aerogear/ups/security/UpsSecurityApplication.java b/project-integrations/aerogear-ups/auth-server/src/main/java/org/aerogear/ups/security/UpsSecurityApplication.java
index eddeace54d..b7b0d568d0 100755
--- a/project-integrations/aerogear-ups/auth-server/src/main/java/org/aerogear/ups/security/UpsSecurityApplication.java
+++ b/project-integrations/aerogear-ups/auth-server/src/main/java/org/aerogear/ups/security/UpsSecurityApplication.java
@@ -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();
}
}
diff --git a/server/pom.xml b/server/pom.xml
index 3e29a02489..1276b48d31 100755
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -225,6 +225,39 @@
provided
+
+
+ org.keycloak
+ keycloak-model-mongo
+ ${project.version}
+
+
+ org.keycloak
+ keycloak-audit-mongo
+ ${project.version}
+
+
+ org.mongodb
+ mongo-java-driver
+
+
+ org.picketlink
+ picketlink-common
+
+
+
+ org.picketlink
+ picketlink-idm-api
+
+
+ org.picketlink
+ picketlink-idm-impl
+
+
+ org.picketlink
+ picketlink-idm-simple-schema
+
+
org.keycloak
diff --git a/server/src/main/resources/META-INF/keycloak-server.json b/server/src/main/resources/META-INF/keycloak-server.json
new file mode 100644
index 0000000000..62405d9d43
--- /dev/null
+++ b/server/src/main/resources/META-INF/keycloak-server.json
@@ -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
+ }
+}
\ No newline at end of file
diff --git a/server/src/main/resources/META-INF/persistence.xml b/server/src/main/resources/META-INF/persistence.xml
index a75390a610..90b17421ac 100755
--- a/server/src/main/resources/META-INF/persistence.xml
+++ b/server/src/main/resources/META-INF/persistence.xml
@@ -25,6 +25,7 @@
+
@@ -36,6 +37,7 @@
+
diff --git a/services/pom.xml b/services/pom.xml
index af526e7029..6b8ceef248 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -102,6 +102,7 @@
jboss-servlet-api_3.0_spec
provided
+
org.jboss.logging
jboss-logging
diff --git a/services/src/main/java/org/keycloak/services/DefaultProviderSession.java b/services/src/main/java/org/keycloak/services/DefaultProviderSession.java
index cd6a9c92a4..aee7a41f50 100755
--- a/services/src/main/java/org/keycloak/services/DefaultProviderSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultProviderSession.java
@@ -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 Stian Thorgersen
*/
public class DefaultProviderSession implements ProviderSession {
+
private DefaultProviderSessionFactory factory;
private Map providers = new HashMap();
@@ -21,8 +24,16 @@ public class DefaultProviderSession implements ProviderSession {
}
public T getProvider(Class 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 providerFactory = factory.getProviderFactory(clazz);
+ if (providerFactory != null) {
+ provider = providerFactory.create(this);
+ providers.put(hash, provider);
+ }
+ }
+ return provider;
}
public T getProvider(Class clazz, String id) {
@@ -39,15 +50,14 @@ public class DefaultProviderSession implements ProviderSession {
}
public Set listProviderIds(Class clazz) {
- return factory.providerIds(clazz);
+ return factory.getAllProviderIds(clazz);
}
@Override
public Set getAllProviders(Class clazz) {
- Set providerIds = listProviderIds(clazz);
Set providers = new HashSet();
- for (String providerId : providerIds) {
- providers.add(getProvider(clazz, providerId));
+ for (String id : listProviderIds(clazz)) {
+ providers.add(getProvider(clazz, id));
}
return providers;
}
diff --git a/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java
index fbc0993c06..128c27200c 100755
--- a/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java
@@ -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, ProviderFactoryLoader> loaders = new HashMap, ProviderFactoryLoader>();
- private Map, String> defaultFactories = new HashMap, String>();
+ private static final Logger log = Logger.getLogger(DefaultProviderSessionFactory.class);
+
+ private Map, String> provider = new HashMap, String>();
+ private Map, Map> factoriesMap = new HashMap, Map>();
+
+ public void init() {
+ for (Spi spi : ServiceLoader.load(Spi.class)) {
+ Map factories = new HashMap();
+ 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);
}
+ ProviderFactory getProviderFactory(Class clazz) {
+ return getProviderFactory(clazz, provider.get(clazz));
+ }
+
+ ProviderFactory getProviderFactory(Class clazz, String id) {
+ return factoriesMap.get(clazz).get(id);
+ }
+
+ Set getAllProviderIds(Class clazz) {
+ Set ids = new HashSet();
+ 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 factories : factoriesMap.values()) {
+ for (ProviderFactory factory : factories.values()) {
+ factory.close();
+ }
}
}
- public ProviderFactory getProviderFactory(Class clazz) {
- String id = defaultFactories.get(clazz);
- if (id == null) {
- return null;
- }
- return getProviderFactory(clazz, id);
- }
-
- public ProviderFactory getProviderFactory(Class clazz, String id) {
- ProviderFactoryLoader loader = getLoader(clazz);
- return loader != null ? loader.find(id) : null;
- }
-
- public Set 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 ProviderFactoryLoader getLoader(Class clazz) {
- return loaders.get(clazz);
- }
-
}
diff --git a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
index 97a5f0f9c0..68106f975b 100755
--- a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
+++ b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
@@ -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();
}
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 1ef7d7c693..653cdc6f93 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -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);
diff --git a/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java b/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
index a941f89ad7..f231825ee7 100755
--- a/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
+++ b/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
@@ -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);
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 43e9630e3c..19c441fbfc 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -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;
diff --git a/services/src/main/java/org/keycloak/services/resources/Cors.java b/services/src/main/java/org/keycloak/services/resources/Cors.java
index a391ab36fe..9dbcd39188 100755
--- a/services/src/main/java/org/keycloak/services/resources/Cors.java
+++ b/services/src/main/java/org/keycloak/services/resources/Cors.java
@@ -1,5 +1,7 @@
package org.keycloak.services.resources;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -8,7 +10,7 @@ import javax.ws.rs.core.Response.ResponseBuilder;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.util.CollectionUtil;
/**
* @author Stian Thorgersen
@@ -16,20 +18,25 @@ import org.keycloak.models.UserModel;
public class Cors {
public static final long DEFAULT_MAX_AGE = TimeUnit.HOURS.toSeconds(1);
- public static final String DEFAULT_ALLOW_METHODS = "GET, OPTIONS";
+ public static final String DEFAULT_ALLOW_METHODS = "GET, HEAD, OPTIONS";
+ public static final String DEFAULT_ALLOW_HEADERS = "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers";
- public static final String ORIGIN = "Origin";
+ public static final String ORIGIN_HEADER = "Origin";
+ public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
+ public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
+
private HttpRequest request;
private ResponseBuilder response;
private Set allowedOrigins;
- private String[] allowedMethods;
+ private Set allowedMethods;
+ private Set exposedHeaders;
private boolean preflight;
private boolean auth;
@@ -61,12 +68,17 @@ public class Cors {
}
public Cors allowedMethods(String... allowedMethods) {
- this.allowedMethods = allowedMethods;
+ this.allowedMethods = new HashSet(Arrays.asList(allowedMethods));
+ return this;
+ }
+
+ public Cors exposedHeaders(String... exposedHeaders) {
+ this.exposedHeaders = new HashSet(Arrays.asList(exposedHeaders));
return this;
}
public Response build() {
- String origin = request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN);
+ String origin = request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN_HEADER);
if (origin == null) {
return response.build();
}
@@ -78,21 +90,20 @@ public class Cors {
response.header(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
if (allowedMethods != null) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < allowedMethods.length; i++) {
- if (i > 0) {
- sb.append(", ");
- }
- sb.append(allowedMethods[i]);
- }
- response.header(ACCESS_CONTROL_ALLOW_METHODS, sb.toString());
+ response.header(ACCESS_CONTROL_ALLOW_METHODS, CollectionUtil.join(allowedMethods));
} else {
response.header(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
}
+ if (exposedHeaders != null) {
+ response.header(ACCESS_CONTROL_EXPOSE_HEADERS, CollectionUtil.join(exposedHeaders));
+ }
+
response.header(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
if (auth) {
- response.header(ACCESS_CONTROL_ALLOW_HEADERS, "Authorization");
+ response.header(ACCESS_CONTROL_ALLOW_HEADERS, String.format("%s, %s", DEFAULT_ALLOW_HEADERS, AUTHORIZATION_HEADER));
+ } else {
+ response.header(ACCESS_CONTROL_ALLOW_HEADERS, DEFAULT_ALLOW_HEADERS);
}
response.header(ACCESS_CONTROL_MAX_AGE, DEFAULT_MAX_AGE);
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 63396a19b4..dec47523fc 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -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