keycloak-aplcache

Added 'keycloak-server.json' for configuring the server Added

5/15/2014 1:01:19 PM

Changes

core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java 102(+0 -102)

model/api/src/main/java/org/keycloak/models/Config.java 183(+0 -183)

model/api/src/main/java/org/keycloak/models/utils/ModelProviderUtils.java 49(+0 -49)

model/jpa/pom.xml 18(+0 -18)

model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java 41(+0 -41)

model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider 1(+0 -1)

model/mongo/pom.xml 30(+9 -21)

model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProvider.java 21(+0 -21)

model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java 20(+0 -20)

model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java 104(+0 -104)

model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/MongoModelProvider.java 27(+0 -27)

model/mongo/src/main/resources/META-INF/services/org.keycloak.models.ModelProvider 1(+0 -1)

model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java 31(+0 -31)

model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java 23(+0 -23)

model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java 140(+0 -140)

model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java 114(+0 -114)

server/pom.xml 33(+33 -0)

services/pom.xml 1(+1 -0)

Details

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 1ccdca8..625074f 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 0000000..e2f0b9c
--- /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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuditListenerSpi implements Spi {
+
+    @Override
+    public String getName() {
+        return "audit-listener";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return AuditListener.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return AuditListenerFactory.class;
+    }
+
+}
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 0000000..249f7ea
--- /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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuditProviderSpi implements Spi {
+
+    @Override
+    public String getName() {
+        return "audit";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return AuditProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return AuditProviderFactory.class;
+    }
+
+}
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 0000000..2a1aeb8
--- /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 1f936af..1bafa9f 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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -21,7 +21,7 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
     }
 
     @Override
-    public void init() {
+    public void init(Config.Scope config) {
     }
 
     @Override
@@ -33,9 +33,4 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
         return ID;
     }
 
-    @Override
-    public boolean lazyLoad() {
-        return false;
-    }
-
 }
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 c7d7a1a..01f72e2 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 8f78fb4..4ffcda1 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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -29,11 +32,28 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
     }
 
     @Override
-    public void init() {
+    public void init(Config.Scope config) {
         try {
-            client = new MongoClient(System.getProperty(MONGO_HOST, "localhost"), Integer.parseInt(System.getProperty(MONGO_PORT, "27017")));
+            String host = config.get("host", ServerAddress.defaultHost());
+            int port = config.getInt("port", ServerAddress.defaultPort());
+            String dbName = config.get("db", "keycloak-audit");
+            boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
+
+            String user = config.get("user");
+            String password = config.get("password");
+            if (user != null && password != null) {
+                MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
+                client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
+            } else {
+                client = new MongoClient(host, port);
+            }
+
             client.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
-            db = client.getDB(System.getProperty(MONGO_DB_NAME, "keycloak-audit"));
+            db = client.getDB(dbName);
+
+            if (clearOnStartup) {
+                db.getCollection("audit").drop();
+            }
         } catch (UnknownHostException e) {
             throw new RuntimeException(e);
         }
@@ -49,9 +69,4 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
         return ID;
     }
 
-    @Override
-    public boolean lazyLoad() {
-        return true;
-    }
-
 }
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 3de7473..b24ee37 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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -23,9 +24,14 @@ public abstract class AbstractAuditProviderTest {
 
     @Before
     public void before() {
-        ProviderFactoryLoader<AuditProvider> loader = ProviderFactoryLoader.create(AuditProviderFactory.class);
-        factory = loader.find(getProviderId());
-        factory.init();
+        String providerId = getProviderId();
+        ServiceLoader<AuditProviderFactory> factories = ServiceLoader.load(AuditProviderFactory.class);
+        for (AuditProviderFactory f : factories) {
+            if (f.getId().equals(providerId)) {
+                factory = f;
+                factory.init(Config.scope("audit", providerId));
+            }
+        }
 
         provider = factory.create(null);
     }
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 0000000..875b150
--- /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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuthenticationSpi implements Spi {
+
+    @Override
+    public String getName() {
+        return "authentication";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return AuthenticationProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return AuthenticationProviderFactory.class;
+    }
+
+}
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 0000000..9305401
--- /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 3f58d4e..4a208c0 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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -17,7 +17,7 @@ public class ExternalModelAuthenticationProviderFactory implements Authenticatio
     }
 
     @Override
-    public void init() {
+    public void init(Config.Scope config) {
     }
 
     @Override
@@ -29,8 +29,4 @@ public class ExternalModelAuthenticationProviderFactory implements Authenticatio
         return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
     }
 
-    @Override
-    public boolean lazyLoad() {
-        return false;
-    }
 }
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 8b9e6c1..47ef637 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 0027be6..ce69bd3 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 db1ece3..29cdb6f 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 0000000..34d0fa4
--- /dev/null
+++ b/core/src/main/java/org/keycloak/Config.java
@@ -0,0 +1,129 @@
+package org.keycloak;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class Config {
+
+    private static ConfigProvider configProvider = new SystemPropertiesConfigProvider();
+
+    public static void init(ConfigProvider configProvider) {
+        Config.configProvider = configProvider;
+    }
+
+    public static String getAdminRealm() {
+        return configProvider.scope("admin").get("realm", "keycloak-admin");
+    }
+
+    public static String getProvider(String spi) {
+        return configProvider.getProvider(spi);
+    }
+
+    public static Scope scope(String... scope) {
+         return configProvider.scope(scope);
+    }
+
+    public static interface ConfigProvider {
+
+        String getProvider(String spi);
+
+        Scope scope(String... scope);
+
+    }
+
+    public static class SystemPropertiesConfigProvider implements ConfigProvider {
+
+        @Override
+        public String getProvider(String spi) {
+            return System.getProperties().getProperty("keycloak." + spi + ".provider");
+        }
+
+        @Override
+        public Scope scope(String... scope) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("keycloak.");
+            for (String s : scope) {
+                sb.append(s);
+                sb.append(".");
+            }
+            return new SystemPropertiesScope(sb.toString());
+        }
+
+    }
+
+    public static class SystemPropertiesScope implements Scope {
+
+        private String prefix;
+
+        public SystemPropertiesScope(String prefix) {
+            this.prefix = prefix;
+        }
+
+        @Override
+        public String get(String key) {
+            return get(key, null);
+        }
+
+        @Override
+        public String get(String key, String defaultValue) {
+            return System.getProperty(prefix + key, defaultValue);
+        }
+
+        @Override
+        public Integer getInt(String key) {
+            return getInt(key, null);
+        }
+
+        @Override
+        public Integer getInt(String key, Integer defaultValue) {
+            String v = get(key, null);
+            return v != null ? Integer.parseInt(v) : defaultValue;
+        }
+
+        @Override
+        public Long getLong(String key) {
+            return getLong(key, null);
+        }
+
+        @Override
+        public Long getLong(String key, Long defaultValue) {
+            String v = get(key, null);
+            return v != null ? Long.parseLong(v) : defaultValue;
+        }
+
+        @Override
+        public Boolean getBoolean(String key) {
+            return getBoolean(key, null);
+        }
+
+        @Override
+        public Boolean getBoolean(String key, Boolean defaultValue) {
+            String v = get(key, null);
+            return v != null ? Boolean.parseBoolean(v) : defaultValue;
+        }
+
+    }
+
+    /**
+     * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+     */
+    public static interface Scope {
+
+        String get(String key);
+
+        String get(String key, String defaultValue);
+
+        Integer getInt(String key);
+
+        Integer getInt(String key, Integer defaultValue);
+
+        Long getLong(String key);
+
+        Long getLong(String key, Long defaultValue);
+
+        Boolean getBoolean(String key);
+
+        Boolean getBoolean(String key, Boolean defaultValue);
+
+    }
+}
diff --git a/core/src/main/java/org/keycloak/provider/ProviderFactory.java b/core/src/main/java/org/keycloak/provider/ProviderFactory.java
index 996d2c5..0e49732 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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -7,12 +9,10 @@ public interface ProviderFactory<T extends Provider> {
 
     public T create(ProviderSession providerSession);
 
-    public void init();
+    public void init(Config.Scope config);
 
     public void close();
 
     public String getId();
 
-    public boolean lazyLoad();
-
 }
diff --git a/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java b/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java
index 2e347df..93536d0 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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -11,12 +9,6 @@ public interface ProviderSessionFactory {
 
     void close();
 
-    <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz);
-
-    <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id);
-
-    Set<String> providerIds(Class<? extends Provider> clazz);
-
     void init();
 
 }
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 0000000..03b9afc
--- /dev/null
+++ b/core/src/main/java/org/keycloak/provider/Spi.java
@@ -0,0 +1,12 @@
+package org.keycloak.provider;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface Spi {
+
+    public String getName();
+    public Class<? extends Provider> getProviderClass();
+    public Class<? extends ProviderFactory> getProviderFactoryClass();
+
+}
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 0000000..d46f699
--- /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 <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="Scott.Stark@jboss.org">Scott Stark</a>
+ * @author <a href="claudio.vesco@previnet.it">Claudio Vesco</a>
+ * @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
+ * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
+ * @version <tt>$Revision: 2898 $</tt> 
+ */
+public final class StringPropertyReplacer
+{
+    /** New line string constant */
+    public static final String NEWLINE = System.getProperty("line.separator", "\n");
+
+    /** File separator value */
+    private static final String FILE_SEPARATOR = File.separator;
+
+    /** Path separator value */
+    private static final String PATH_SEPARATOR = File.pathSeparator;
+
+    /** File separator alias */
+    private static final String FILE_SEPARATOR_ALIAS = "/";
+
+    /** Path separator alias */
+    private static final String PATH_SEPARATOR_ALIAS = ":";
+
+    // States used in property parsing
+    private static final int NORMAL = 0;
+    private static final int SEEN_DOLLAR = 1;
+    private static final int IN_BRACKET = 2;
+
+    /**
+     * Go through the input string and replace any occurance of ${p} with
+     * the System.getProperty(p) value. If there is no such property p defined,
+     * then the ${p} reference will remain unchanged.
+     *
+     * If the property reference is of the form ${p:v} and there is no such property p,
+     * then the default value v will be returned.
+     *
+     * If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
+     * the primary and the secondary properties will be tried in turn, before
+     * returning either the unchanged input, or the default value.
+     *
+     * The property ${/} is replaced with System.getProperty("file.separator")
+     * value and the property ${:} is replaced with System.getProperty("path.separator").
+     *
+     * @param string - the string with possible ${} references
+     * @return the input string with all property references replaced if any.
+     *    If there are no valid references the input string will be returned.
+     */
+    public static String replaceProperties(final String string)
+    {
+        return replaceProperties(string, null);
+    }
+
+    /**
+     * Go through the input string and replace any occurance of ${p} with
+     * the props.getProperty(p) value. If there is no such property p defined,
+     * then the ${p} reference will remain unchanged.
+     *
+     * If the property reference is of the form ${p:v} and there is no such property p,
+     * then the default value v will be returned.
+     *
+     * If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
+     * the primary and the secondary properties will be tried in turn, before
+     * returning either the unchanged input, or the default value.
+     *
+     * The property ${/} is replaced with System.getProperty("file.separator")
+     * value and the property ${:} is replaced with System.getProperty("path.separator").
+     *
+     * @param string - the string with possible ${} references
+     * @param props - the source for ${x} property ref values, null means use System.getProperty()
+     * @return the input string with all property references replaced if any.
+     *    If there are no valid references the input string will be returned.
+     */
+    public static String replaceProperties(final String string, final Properties props)
+    {
+        final char[] chars = string.toCharArray();
+        StringBuffer buffer = new StringBuffer();
+        boolean properties = false;
+        int state = NORMAL;
+        int start = 0;
+        for (int i = 0; i < chars.length; ++i)
+        {
+            char c = chars[i];
+
+            // Dollar sign outside brackets
+            if (c == '$' && state != IN_BRACKET)
+                state = SEEN_DOLLAR;
+
+                // Open bracket immediatley after dollar
+            else if (c == '{' && state == SEEN_DOLLAR)
+            {
+                buffer.append(string.substring(start, i - 1));
+                state = IN_BRACKET;
+                start = i - 1;
+            }
+
+            // No open bracket after dollar
+            else if (state == SEEN_DOLLAR)
+                state = NORMAL;
+
+                // Closed bracket after open bracket
+            else if (c == '}' && state == IN_BRACKET)
+            {
+                // No content
+                if (start + 2 == i)
+                {
+                    buffer.append("${}"); // REVIEW: Correct?
+                }
+                else // Collect the system property
+                {
+                    String value = null;
+
+                    String key = string.substring(start + 2, i);
+
+                    // check for alias
+                    if (FILE_SEPARATOR_ALIAS.equals(key))
+                    {
+                        value = FILE_SEPARATOR;
+                    }
+                    else if (PATH_SEPARATOR_ALIAS.equals(key))
+                    {
+                        value = PATH_SEPARATOR;
+                    }
+                    else
+                    {
+                        // check from the properties
+                        if (props != null)
+                            value = props.getProperty(key);
+                        else
+                            value = System.getProperty(key);
+
+                        if (value == null)
+                        {
+                            // Check for a default value ${key:default}
+                            int colon = key.indexOf(':');
+                            if (colon > 0)
+                            {
+                                String realKey = key.substring(0, colon);
+                                if (props != null)
+                                    value = props.getProperty(realKey);
+                                else
+                                    value = System.getProperty(realKey);
+
+                                if (value == null)
+                                {
+                                    // Check for a composite key, "key1,key2"
+                                    value = resolveCompositeKey(realKey, props);
+
+                                    // Not a composite key either, use the specified default
+                                    if (value == null)
+                                        value = key.substring(colon+1);
+                                }
+                            }
+                            else
+                            {
+                                // No default, check for a composite key, "key1,key2"
+                                value = resolveCompositeKey(key, props);
+                            }
+                        }
+                    }
+
+                    if (value != null)
+                    {
+                        properties = true;
+                        buffer.append(value);
+                    }
+                    else
+                    {
+                        buffer.append("${");
+                        buffer.append(key);
+                        buffer.append('}');
+                    }
+
+                }
+                start = i + 1;
+                state = NORMAL;
+            }
+        }
+
+        // No properties
+        if (properties == false)
+            return string;
+
+        // Collect the trailing characters
+        if (start != chars.length)
+            buffer.append(string.substring(start, chars.length));
+
+        // Done
+        return buffer.toString();
+    }
+
+    /**
+     * Try to resolve a "key" from the provided properties by
+     * checking if it is actually a "key1,key2", in which case
+     * try first "key1", then "key2". If all fails, return null.
+     *
+     * It also accepts "key1," and ",key2".
+     *
+     * @param key the key to resolve
+     * @param props the properties to use
+     * @return the resolved key or null
+     */
+    private static String resolveCompositeKey(String key, Properties props)
+    {
+        String value = null;
+
+        // Look for the comma
+        int comma = key.indexOf(',');
+        if (comma > -1)
+        {
+            // If we have a first part, try resolve it
+            if (comma > 0)
+            {
+                // Check the first part
+                String key1 = key.substring(0, comma);
+                if (props != null)
+                    value = props.getProperty(key1);
+                else
+                    value = System.getProperty(key1);
+            }
+            // Check the second part, if there is one and first lookup failed
+            if (value == null && comma < key.length() - 1)
+            {
+                String key2 = key.substring(comma + 1);
+                if (props != null)
+                    value = props.getProperty(key2);
+                else
+                    value = System.getProperty(key2);
+            }
+        }
+        // Return whatever we've found or null
+        return value;
+    }
+}
\ 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 873fd6e..70f14f4 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 <literal>mongo</literal> instead of default <literal>jpa</literal> model, and you may also specify
                 host, port and name of mongo database. So you can start keycloak with the command like this:
 <programlisting><![CDATA[
-./standalone.sh -Dkeycloak.model=mongo -Dkeycloak.mongo.host=localhost
--Dkeycloak.mongo.port=27017 -Dkeycloak.mongo.db=keycloak
+./standalone.sh -Dkeycloak.model=mongo -Dkeycloak.model.mongo.host=localhost
+-Dkeycloak.model.mongoport=27017 -Dkeycloak.model.mongo.db=keycloak
 ]]></programlisting>
                 Note that when you install MongoDB on your laptop, it's usually on localhost/270717 by default. That's why properties
-                <literal>keycloak.mongo.host</literal> and <literal>keycloak.mongo.port</literal> are not mandatory, but they already have
-                default values <literal>localhost</literal> and <literal>27017</literal> . Similarly property <literal>keycloak.mongo.db</literal>
+                <literal>keycloak.model.mongo.host</literal> and <literal>keycloak.model.mongo.port</literal> are not mandatory, but they already have
+                default values <literal>localhost</literal> and <literal>27017</literal> . Similarly property <literal>keycloak.model.mongo.db</literal>
                 has default value <literal>keycloak</literal> for name of underlying database. So the example above could be simplified like:
 <programlisting><![CDATA[
 ./standalone.sh -Dkeycloak.model=mongo
diff --git a/export-import/export-import-api/pom.xml b/export-import/export-import-api/pom.xml
index 7f94100..e4ed0ad 100644
--- a/export-import/export-import-api/pom.xml
+++ b/export-import/export-import-api/pom.xml
@@ -16,6 +16,12 @@
     <dependencies>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-api</artifactId>
             <version>${project.version}</version>
             <scope>provided</scope>
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 9ada46b..9798370 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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 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 a4898e5..17a566e 100644
--- a/export-import/export-import-impl/pom.xml
+++ b/export-import/export-import-impl/pom.xml
@@ -33,13 +33,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-audit-api</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>jaxrs-api</artifactId>
             <scope>provided</scope>
@@ -122,6 +115,12 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-tests</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
             <artifactId>hibernate-jpa-2.0-api</artifactId>
             <scope>test</scope>
@@ -149,10 +148,10 @@
     </dependencies>
 
     <properties>
-        <keycloak.mongo.host>localhost</keycloak.mongo.host>
-        <keycloak.mongo.port>27018</keycloak.mongo.port>
-        <keycloak.mongo.db>keycloak</keycloak.mongo.db>
-        <keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
+        <keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
+        <keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
+        <keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
+        <keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
     </properties>
 
     <build>
@@ -179,10 +178,10 @@
                         </goals>
                         <configuration>
                             <systemPropertyVariables>
-                                <keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
-                                <keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
-                                <keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
-                                <keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
+                                <keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
+                                <keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
+                                <keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
+                                <keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
                             </systemPropertyVariables>
                         </configuration>
                     </execution>
@@ -207,7 +206,7 @@
                             <goal>start</goal>
                         </goals>
                         <configuration>
-                            <port>${keycloak.mongo.port}</port>
+                            <port>${keycloak.model.mongo.port}</port>
                             <logging>file</logging>
                             <logFile>${project.build.directory}/mongodb.log</logFile>
                         </configuration>
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 0000000..d87b55c
--- /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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ExportImportConfig {
+
+    public static final String ACTION = "keycloak.migration.action";
+    public static final String PROVIDER = "keycloak.migration.provider";
+    public static final String PROVIDER_DEFAULT = "zip";
+
+    // used for "directory" provider
+    public static final String DIR = "keycloak.migration.dir";
+    // used for "zip" provider
+    public static final String FILE = "keycloak.migration.zipFile";
+    public static final String PASSWORD = "keycloak.migration.zipPassword";
+
+    public static String getAction() {
+        return System.getProperty(ACTION);
+    }
+
+    public static void setAction(String exportImportAction) {
+        System.setProperty(ACTION, exportImportAction);
+    }
+
+    public static String getProvider() {
+        return System.getProperty(PROVIDER, PROVIDER_DEFAULT);
+    }
+
+    public static void setProvider(String exportImportProvider) {
+        System.setProperty(PROVIDER, exportImportProvider);
+    }
+
+    public static String getDir() {
+        return System.getProperty(DIR);
+    }
+
+    public static String getZipFile() {
+        return System.getProperty(FILE);
+    }
+
+    public static void setZipFile(String exportImportZipFile) {
+        System.setProperty(FILE, exportImportZipFile);
+    }
+
+    public static String getZipPassword() {
+        return System.getProperty(PASSWORD);
+    }
+
+    public static void setZipPassword(String exportImportZipPassword) {
+        System.setProperty(PASSWORD, exportImportZipPassword);
+    }
+
+}
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 32e0b84..de84633 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<ExportImportIOProvider> providers = ProviderLoader.load(ExportImportIOProvider.class);
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 962c3ac..b785c41 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 837157e..31883ac 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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -22,8 +22,8 @@ public class EncryptedZIPIOProvider implements ExportImportIOProvider {
 
     @Override
     public ExportWriter getExportWriter() {
-        String zipFile = Config.getExportImportZipFile();
-        String zipPassword = Config.getExportImportZipPassword();
+        String zipFile = ExportImportConfig.getZipFile();
+        String zipPassword = ExportImportConfig.getZipPassword();
         logger.infof("Using zip for export: " + zipFile);
 
         if (zipFile==null || zipPassword==null) {
@@ -35,8 +35,8 @@ public class EncryptedZIPIOProvider implements ExportImportIOProvider {
 
     @Override
     public ImportReader getImportReader() {
-        String zipFile = Config.getExportImportZipFile();
-        String zipPassword = Config.getExportImportZipPassword();
+        String zipFile = ExportImportConfig.getZipFile();
+        String zipPassword = ExportImportConfig.getZipPassword();
         logger.infof("Using zip for import: " + zipFile);
 
         if (zipFile==null || zipPassword==null) {
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 3bfc9aa..15f9fae 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/test/java/org/keycloak/exportimport/ExportImportTestBase.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java
index 1e39f24..49817c7 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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public abstract class ExportImportTestBase {
 
-    protected KeycloakSessionFactory factory;
+    protected ProviderSessionFactory factory;
 
+    protected ProviderSession providerSession;
     protected KeycloakSession identitySession;
     protected RealmManager realmManager;
 
+    @After
+    public void after() {
+        System.getProperties().remove("keycloak.model.provider");
+    }
+
     @Test
     public void testExportImport() throws Exception {
         // Init JPA model
-        Config.setModelProvider(getExportModelProvider());
-        factory = KeycloakApplication.createSessionFactory();
+        System.setProperty("keycloak.model.provider", getExportModelProvider());
+        factory = KeycloakApplication.createProviderSessionFactory();
 
         // Bootstrap admin realm
         beginTransaction();
@@ -59,8 +66,8 @@ public abstract class ExportImportTestBase {
         factory.close();
 
         // Bootstrap mongo session and factory
-        Config.setModelProvider(getImportModelProvider());
-        factory = KeycloakApplication.createSessionFactory();
+        System.setProperty("keycloak.model.provider", getImportModelProvider());
+        factory = KeycloakApplication.createProviderSessionFactory();
 
         // Full import of previous export into mongo
         importModel(factory);
@@ -83,19 +90,20 @@ public abstract class ExportImportTestBase {
 
     protected abstract String getImportModelProvider();
 
-    protected abstract void exportModel(KeycloakSessionFactory factory);
+    protected abstract void exportModel(ProviderSessionFactory factory);
 
-    protected abstract void importModel(KeycloakSessionFactory factory);
+    protected abstract void importModel(ProviderSessionFactory factory);
 
     protected void beginTransaction() {
-        identitySession = factory.createSession();
+        providerSession = factory.createSession();
+        identitySession = providerSession.getProvider(KeycloakSession.class);
         identitySession.getTransaction().begin();
         realmManager = new RealmManager(identitySession);
     }
 
     protected void commitTransaction() {
         identitySession.getTransaction().commit();
-        identitySession.close();
+        providerSession.close();
     }
 
     protected ExportImportProvider getExportImportProvider() {
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 8175bdb..52ee054 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 e715c9c..849c388 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 c64bff6..23f99e3 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<ThemeProvider> 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 a323945..8a8659c 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 a76b328..101851c 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/KeycloakSession.java b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
index 9aa55ee..aa61bec 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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public interface KeycloakSession {
+public interface KeycloakSession extends Provider {
     KeycloakTransaction getTransaction();
 
     RealmModel createRealm(String name);
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 3149f9b..dba6d84 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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public interface KeycloakSessionFactory {
-    KeycloakSession createSession();
+public interface KeycloakSessionFactory extends ProviderFactory<KeycloakSession> {
+    KeycloakSession create(ProviderSession providerSession);
     void close();
 }
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 0000000..42586e9
--- /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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ModelSpi implements Spi {
+
+    @Override
+    public String getName() {
+        return "model";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return KeycloakSession.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return KeycloakSessionFactory.class;
+    }
+
+}
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 0000000..48ff59e
--- /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

model/jpa/pom.xml 18(+0 -18)

diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index 15ac823..c12e9cd 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -32,24 +32,6 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-audit-api</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-audit-jpa</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-audit-jboss-logging</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-api</artifactId>
             <version>${project.version}</version>
         </dependency>
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 67ba543..6efe710 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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
-    protected EntityManagerFactory factory;
 
-    public JpaKeycloakSessionFactory(EntityManagerFactory factory) {
-        this.factory = factory;
+    protected EntityManagerFactory emf;
+
+    @Override
+    public void init(Config.Scope config) {
+        emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties());
+    }
+
+    @Override
+    public String getId() {
+        return "jpa";
     }
 
     @Override
-    public KeycloakSession createSession() {
-        return new JpaKeycloakSession(factory.createEntityManager());
+    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/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 0000000..d77ce1b
--- /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

model/mongo/pom.xml 30(+9 -21)

diff --git a/model/mongo/pom.xml b/model/mongo/pom.xml
index 01bce2f..cab3668 100755
--- a/model/mongo/pom.xml
+++ b/model/mongo/pom.xml
@@ -45,18 +45,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-audit-api</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-audit-jboss-logging</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
@@ -103,10 +91,10 @@
     </dependencies>
 
     <properties>
-        <keycloak.mongo.host>localhost</keycloak.mongo.host>
-        <keycloak.mongo.port>27018</keycloak.mongo.port>
-        <keycloak.mongo.db>keycloak</keycloak.mongo.db>
-        <keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
+        <keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
+        <keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
+        <keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
+        <keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
     </properties>
 
     <build>
@@ -133,10 +121,10 @@
                         </goals>
                         <configuration>
                             <systemPropertyVariables>
-                                <keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
-                                <keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
-                                <keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
-                                <keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
+                                <keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
+                                <keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
+                                <keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
+                                <keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
                             </systemPropertyVariables>
                             <dependenciesToScan>
                                 <dependency>org.keycloak:keycloak-model-tests</dependency>
@@ -164,7 +152,7 @@
                             <goal>start</goal>
                         </goals>
                         <configuration>
-                            <port>${keycloak.mongo.port}</port>
+                            <port>${keycloak.model.mongo.port}</port>
                             <logging>file</logging>
                             <logFile>${project.build.directory}/mongodb.log</logFile>
                         </configuration>
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 6feb373..142cdbe 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;
+
+    private MongoStore mongoStore;
+
+    @Override
+    public String getId() {
+        return "mongo";
+    }
+
+    @Override
+    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);
+        }
 
-    public MongoKeycloakSessionFactory(MongoClientProvider provider) {
-        this.mongoClientProvider = provider;
-        this.mongoStore = new MongoStoreImpl(provider.getDB(), provider.clearCollectionsOnStartup(), MANAGED_ENTITY_TYPES);
     }
 
     @Override
-    public KeycloakSession createSession() {
+    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/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 0000000..47363dc
--- /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/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java
index 2f7177b..428d4c8 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 880ce14..a603226 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 0000000..42111da
--- /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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class IdentityManagerSpi implements Spi {
+    @Override
+    public String getName() {
+        return "picketlink-identity-manager";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return IdentityManagerProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return IdentityManagerProviderFactory.class;
+    }
+}
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 0000000..ffcb6e5
--- /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 83b5970..236cff6 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 eddeace..b7b0d56 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();
         }
 
     }

server/pom.xml 33(+33 -0)

diff --git a/server/pom.xml b/server/pom.xml
index 3e29a02..1276b48 100755
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -225,6 +225,39 @@
             <scope>provided</scope>
         </dependency>
 
+        <!-- Mongo dependencies -->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-mongo</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-audit-mongo</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongo-java-driver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-idm-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-idm-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-idm-simple-schema</artifactId>
+        </dependency>
+
         <!-- export/import -->
         <dependency>
             <groupId>org.keycloak</groupId>
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 0000000..62405d9
--- /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 616f8e8..2ec80b4 100755
--- a/server/src/main/resources/META-INF/persistence.xml
+++ b/server/src/main/resources/META-INF/persistence.xml
@@ -24,6 +24,7 @@
 
         <properties>
             <property name="hibernate.hbm2ddl.auto" value="update" />
+            <property name="jboss.as.jpa.managed" value="false" />
         </properties>
     </persistence-unit>
 	
@@ -35,6 +36,7 @@
 
         <properties>
             <property name="hibernate.hbm2ddl.auto" value="update" />
+            <property name="jboss.as.jpa.managed" value="false" />
         </properties>
     </persistence-unit>
 	

services/pom.xml 1(+1 -0)

diff --git a/services/pom.xml b/services/pom.xml
index af526e7..6b8ceef 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -102,6 +102,7 @@
             <artifactId>jboss-servlet-api_3.0_spec</artifactId>
             <scope>provided</scope>
         </dependency>
+
         <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
diff --git a/services/src/main/java/org/keycloak/services/DefaultProviderSession.java b/services/src/main/java/org/keycloak/services/DefaultProviderSession.java
index cd6a9c9..aee7a41 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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class DefaultProviderSession implements ProviderSession {
+
     private DefaultProviderSessionFactory factory;
     private Map<Integer, Provider> providers = new HashMap<Integer, Provider>();
 
@@ -21,8 +24,16 @@ public class DefaultProviderSession implements ProviderSession {
     }
 
     public <T extends Provider> T getProvider(Class<T> clazz) {
-        String id = factory.getDefaultProvider(clazz);
-        return id != null ? getProvider(clazz, id) : null;
+        Integer hash = clazz.hashCode();
+        T provider = (T) providers.get(hash);
+        if (provider == null) {
+            ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz);
+            if (providerFactory != null) {
+                provider = providerFactory.create(this);
+                providers.put(hash, provider);
+            }
+        }
+        return provider;
     }
 
     public <T extends Provider> T getProvider(Class<T> clazz, String id) {
@@ -39,15 +50,14 @@ public class DefaultProviderSession implements ProviderSession {
     }
 
     public <T extends Provider> Set<String> listProviderIds(Class<T> clazz) {
-        return factory.providerIds(clazz);
+        return factory.getAllProviderIds(clazz);
     }
 
     @Override
     public <T extends Provider> Set<T> getAllProviders(Class<T> clazz) {
-        Set<String> providerIds = listProviderIds(clazz);
         Set<T> providers = new HashSet<T>();
-        for (String providerId : providerIds) {
-            providers.add(getProvider(clazz, providerId));
+        for (String id : listProviderIds(clazz)) {
+            providers.add(getProvider(clazz, id));
         }
         return providers;
     }
diff --git a/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java
index fbc0993..128c272 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<Class<? extends Provider>, ProviderFactoryLoader> loaders = new HashMap<Class<? extends Provider>, ProviderFactoryLoader>();
-    private Map<Class<? extends Provider>, String> defaultFactories = new HashMap<Class<? extends Provider>, String>();
+    private static final Logger log = Logger.getLogger(DefaultProviderSessionFactory.class);
 
-    public ProviderSession createSession() {
-        return new DefaultProviderSession(this);
-    }
+    private Map<Class<? extends Provider>, String> provider = new HashMap<Class<? extends Provider>, String>();
+    private Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<Class<? extends Provider>, Map<String, ProviderFactory>>();
 
-    public void close() {
-        for (ProviderFactoryLoader loader : loaders.values()) {
-            loader.close();
+    public void init() {
+        for (Spi spi : ServiceLoader.load(Spi.class)) {
+            Map<String, ProviderFactory> factories = new HashMap<String, ProviderFactory>();
+            factoriesMap.put(spi.getProviderClass(), factories);
+
+            String provider = Config.getProvider(spi.getName());
+            if (provider != null) {
+                this.provider.put(spi.getProviderClass(), provider);
+
+                ProviderFactory factory = loadProviderFactory(spi, provider);
+                Config.Scope scope = Config.scope(spi.getName(), provider);
+                factory.init(scope);
+                log.debug("Initialized " + factory.getClass().getName() + " (config = " + scope + ")");
+
+                factories.put(factory.getId(), factory);
+
+                log.info("Loaded SPI " + spi.getName() + " (provider = " + provider + ")");
+            } else {
+                for (ProviderFactory factory : ServiceLoader.load(spi.getProviderFactoryClass())) {
+                    Config.Scope scope = Config.scope(spi.getName(), factory.getId());
+                    factory.init(scope);
+                    log.debug("Initialized " + factory.getClass().getName() + " (config = " + scope + ")");
+
+                    factories.put(factory.getId(), factory);
+                }
+
+                if (factories.size() == 1) {
+                    provider = factories.values().iterator().next().getId();
+                    this.provider.put(spi.getProviderClass(), provider);
+
+                    log.info("Loaded SPI " + spi.getName() + " (provider = " + provider + ")");
+                } else {
+                    log.info("Loaded SPI " + spi.getName() + " (providers = " + factories.keySet() + ")");
+                }
+            }
         }
     }
 
-    public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz) {
-        String id = defaultFactories.get(clazz);
-        if (id == null) {
-            return null;
+    private ProviderFactory loadProviderFactory(Spi spi, String id) {
+        for (ProviderFactory factory : ServiceLoader.load(spi.getProviderFactoryClass())) {
+            if (factory.getId().equals(id)){
+                return factory;
+            }
         }
-        return getProviderFactory(clazz, id);
-    }
-
-    public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
-        ProviderFactoryLoader loader = getLoader(clazz);
-        return loader != null ? loader.find(id) : null;
-    }
-
-    public Set<String> providerIds(Class<? extends Provider> clazz) {
-        ProviderFactoryLoader loader = getLoader(clazz);
-        return loader != null ? loader.providerIds() : null;
+        throw new RuntimeException("Failed to find provider " + id + " for " + spi.getName());
     }
 
-    public String getDefaultProvider(Class<? extends Provider> clazz) {
-        return defaultFactories.get(clazz);
+    public ProviderSession createSession() {
+        return new DefaultProviderSession(this);
     }
 
-    public void registerLoader(Class<? extends Provider> clazz, ProviderFactoryLoader loader) {
-        loaders.put(clazz, loader);
-
+    <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz) {
+         return getProviderFactory(clazz, provider.get(clazz));
     }
 
-    public void registerLoader(Class<? extends Provider> clazz, ProviderFactoryLoader loader, String defaultProvider) {
-        loaders.put(clazz, loader);
-        defaultFactories.put(clazz, defaultProvider);
-
+    <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
+         return factoriesMap.get(clazz).get(id);
     }
 
-    public void init() {
-        for (ProviderFactoryLoader l : loaders.values()) {
-            l.init();
+    <T extends Provider> Set<String> getAllProviderIds(Class<T> clazz) {
+        Set<String> ids = new HashSet<String>();
+        for (ProviderFactory f : factoriesMap.get(clazz).values()) {
+            ids.add(f.getId());
         }
+        return ids;
     }
 
-    private <T extends Provider> ProviderFactoryLoader getLoader(Class<T> clazz) {
-        return loaders.get(clazz);
+    public void close() {
+        for (Map<String, ProviderFactory> factories : factoriesMap.values()) {
+            for (ProviderFactory factory : factories.values()) {
+                factory.close();
+            }
+        }
     }
 
 }
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 97a5f0f..68106f9 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 1ef7d7c..653cdc6 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 a941f89..f231825 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 43e9630..19c441f 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/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
index 889990f..ad5cd03 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
@@ -10,14 +10,12 @@ import org.keycloak.freemarker.Theme;
 import org.keycloak.freemarker.ThemeLoader;
 import org.keycloak.models.AdminRoles;
 import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.Config;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.provider.ProviderSession;
-import org.keycloak.services.ForbiddenException;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.ApplicationManager;
 import org.keycloak.services.managers.RealmManager;
@@ -280,12 +278,7 @@ public class AdminConsole {
 
         try {
             //logger.info("getting resource: " + path + " uri: " + uriInfo.getRequestUri().toString());
-            String themeName = realm.getAdminTheme();
-            if (themeName == null || themeName.trim().equals("")) {
-                themeName = Config.getThemeAdmin();
-            }
-
-            Theme theme = ThemeLoader.createTheme(themeName, Theme.Type.ADMIN);
+            Theme theme = ThemeLoader.createTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
             InputStream resource = theme.getResourceAsStream(path);
             if (resource != null) {
                 String contentType = mimeTypes.getContentType(path);
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 63396a1..dec4752 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<Object> singletons = new HashSet<Object>();
     protected Set<Class<?>> classes = new HashSet<Class<?>>();
 
-    protected KeycloakSessionFactory factory;
     protected ProviderSessionFactory providerSessionFactory;
     protected String contextPath;
 
     public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
+        loadConfig();
+
+        this.providerSessionFactory = createProviderSessionFactory();
+
         dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
         this.contextPath = context.getContextPath();
-        this.factory = createSessionFactory();
-        BruteForceProtector protector = new BruteForceProtector(factory);
+        BruteForceProtector protector = new BruteForceProtector(providerSessionFactory);
         dispatcher.getDefaultContextObjects().put(BruteForceProtector.class, protector);
         ResteasyProviderFactory.pushContext(BruteForceProtector.class, protector); // for injection
         protector.start();
         context.setAttribute(BruteForceProtector.class.getName(), protector);
-        this.providerSessionFactory = createProviderSessionFactory();
-        context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
-
         context.setAttribute(ProviderSessionFactory.class.getName(), this.providerSessionFactory);
 
         TokenManager tokenManager = new TokenManager();
@@ -95,7 +86,7 @@ public class KeycloakApplication extends Application {
 
         setupDefaultRealm(context.getContextPath());
 
-        setupScheduledTasks(providerSessionFactory, factory);
+        setupScheduledTasks(providerSessionFactory);
         importRealms(context);
 
         checkExportImportProvider();
@@ -115,55 +106,38 @@ public class KeycloakApplication extends Application {
         return uriInfo.getBaseUriBuilder().replacePath(getContextPath()).build();
     }
 
-    protected void setupDefaultRealm(String contextPath) {
-        new ApplianceBootstrap().bootstrap(factory, contextPath);
-    }
-
+    protected void loadConfig() {
+        try {
+            URL config = Thread.currentThread().getContextClassLoader().getResource("META-INF/keycloak-server.json");
 
-    public static KeycloakSessionFactory createSessionFactory() {
-        ModelProvider provider = ModelProviderUtils.getConfiguredModelProvider();
+            if (config != null) {
+                JsonNode node = new ObjectMapper().readTree(config);
+                Config.init(new JsonConfigProvider(node));
 
-        if (provider != null) {
-            log.debug("Model provider: " + provider.getId());
-            return provider.createFactory();
+                log.info("Loaded config from " + config);
+                return;
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to load config", e);
         }
+    }
 
-        throw new RuntimeException("Model provider not found");
+    protected void setupDefaultRealm(String contextPath) {
+        new ApplianceBootstrap().bootstrap(providerSessionFactory, contextPath);
     }
 
     public static DefaultProviderSessionFactory createProviderSessionFactory() {
         DefaultProviderSessionFactory factory = new DefaultProviderSessionFactory();
-
-        factory.registerLoader(AuditProvider.class, ProviderFactoryLoader.create(AuditProviderFactory.class), Config.getAuditProvider());
-        factory.registerLoader(AuditListener.class, ProviderFactoryLoader.create(AuditListenerFactory.class));
-        factory.registerLoader(TimerProvider.class, ProviderFactoryLoader.create(TimerProviderFactory.class), Config.getTimerProvider());
-        try {
-            Class identityManagerProvider = Class.forName("org.keycloak.picketlink.IdentityManagerProvider");
-            Class identityManagerProviderFactory = Class.forName("org.keycloak.picketlink.IdentityManagerProviderFactory");
-            factory.registerLoader(identityManagerProvider, ProviderFactoryLoader.create(identityManagerProviderFactory), Config.getIdentityManagerProvider());
-        } catch (ClassNotFoundException e) {
-            log.warn("Picketlink libraries not installed for IdentityManagerProviderFactory");
-        }
-
-        factory.registerLoader(AuthenticationProvider.class, ProviderFactoryLoader.create(AuthenticationProviderFactory.class));
         factory.init();
-
         return factory;
     }
 
-    public static void setupScheduledTasks(final ProviderSessionFactory providerSessionFactory, final KeycloakSessionFactory keycloakSessionFactory) {
-        ProviderFactory<TimerProvider> timerFactory = providerSessionFactory.getProviderFactory(TimerProvider.class);
-        if (timerFactory == null) {
-            log.error("Can't setup schedule tasks, no timer provider found");
-            return;
-        }
-        TimerProvider timer = timerFactory.create(null);
-        timer.schedule(new ScheduledTaskRunner(keycloakSessionFactory, providerSessionFactory, new ClearExpiredAuditEvents()), Config.getAuditExpirationSchedule());
-        timer.schedule(new ScheduledTaskRunner(keycloakSessionFactory, providerSessionFactory, new ClearExpiredUserSessions()), Config.getUserExpirationSchedule());
-    }
+    public static void setupScheduledTasks(final ProviderSessionFactory providerSessionFactory) {
+        long interval = Config.scope("scheduled").getLong("interval") * 1000;
 
-    public KeycloakSessionFactory getFactory() {
-        return factory;
+        TimerProvider timer = providerSessionFactory.createSession().getProvider(TimerProvider.class);
+        timer.schedule(new ScheduledTaskRunner(providerSessionFactory, new ClearExpiredAuditEvents()), interval);
+        timer.schedule(new ScheduledTaskRunner(providerSessionFactory, new ClearExpiredUserSessions()), interval);
     }
 
     public ProviderSessionFactory getProviderSessionFactory() {
@@ -215,7 +189,8 @@ public class KeycloakApplication extends Application {
     }
 
     public void importRealm(RealmRepresentation rep, String from) {
-        KeycloakSession session = factory.createSession();
+        ProviderSession providerSession = providerSessionFactory.createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         try {
             session.getTransaction().begin();
             RealmManager manager = new RealmManager(session);
@@ -238,7 +213,7 @@ public class KeycloakApplication extends Application {
 
             session.getTransaction().commit();
         } finally {
-            session.close();
+            providerSession.close();
         }
     }
 
@@ -255,7 +230,7 @@ public class KeycloakApplication extends Application {
 
         if (providers.hasNext()) {
             ExportImportProvider exportImport = providers.next();
-            exportImport.checkExportImport(factory);
+            exportImport.checkExportImport(providerSessionFactory);
         } else {
             log.warn("No ExportImportProvider found!");
         }
diff --git a/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java b/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java
index 1caa290..275b43b 100644
--- a/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java
+++ b/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java
@@ -13,20 +13,18 @@ public class ScheduledTaskRunner implements Runnable {
 
     private static final Logger logger = Logger.getLogger(ScheduledTaskRunner.class);
 
-    private final KeycloakSessionFactory keycloakSessionFactory;
     private final ProviderSessionFactory providerSessionFactory;
     private final ScheduledTask task;
 
-    public ScheduledTaskRunner(KeycloakSessionFactory keycloakSessionFactory, ProviderSessionFactory providerSessionFactory, ScheduledTask task) {
-        this.keycloakSessionFactory = keycloakSessionFactory;
+    public ScheduledTaskRunner(ProviderSessionFactory providerSessionFactory, ScheduledTask task) {
         this.providerSessionFactory = providerSessionFactory;
         this.task = task;
     }
 
     @Override
     public void run() {
-        KeycloakSession keycloakSession = keycloakSessionFactory.createSession();
         ProviderSession providerSession = providerSessionFactory.createSession();
+        KeycloakSession keycloakSession = providerSession.getProvider(KeycloakSession.class);
         try {
             keycloakSession.getTransaction().begin();
             task.run(keycloakSession, providerSession);
@@ -39,11 +37,6 @@ public class ScheduledTaskRunner implements Runnable {
             keycloakSession.getTransaction().rollback();
         } finally {
             try {
-                keycloakSession.close();
-            } catch (Throwable t) {
-                logger.error("Failed to close KeycloakSession", t);
-            }
-            try {
                 providerSession.close();
             } catch (Throwable t) {
                 logger.error("Failed to close ProviderSession", t);
diff --git a/services/src/main/java/org/keycloak/services/util/JsonConfigProvider.java b/services/src/main/java/org/keycloak/services/util/JsonConfigProvider.java
new file mode 100644
index 0000000..181de11
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/util/JsonConfigProvider.java
@@ -0,0 +1,129 @@
+package org.keycloak.services.util;
+
+import org.codehaus.jackson.JsonNode;
+import org.keycloak.Config;
+import org.keycloak.util.StringPropertyReplacer;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class JsonConfigProvider implements Config.ConfigProvider {
+
+    private JsonNode config;
+
+    public JsonConfigProvider(JsonNode config) {
+        this.config = config;
+    }
+
+    @Override
+    public String getProvider(String spi) {
+        JsonNode n = getNode(spi, "provider");
+        return n != null ? StringPropertyReplacer.replaceProperties(n.getTextValue()) : null;
+    }
+
+    @Override
+    public Config.Scope scope(String... path) {
+        return new JsonScope(getNode(path));
+    }
+
+    private JsonNode getNode(String... path) {
+        JsonNode n = config;
+        for (String p : path) {
+            n = n.get(p);
+            if (n == null) {
+                return null;
+            }
+        }
+        return n;
+    }
+
+    public class JsonScope implements Config.Scope {
+
+        private JsonNode config;
+
+        public JsonScope(JsonNode config) {
+            this.config = config;
+        }
+
+        @Override
+        public String get(String key) {
+            return get(key, null);
+        }
+
+        @Override
+        public String get(String key, String defaultValue) {
+            if (config == null) {
+                return defaultValue;
+            }
+            JsonNode n = config.get(key);
+            if (n == null) {
+                return defaultValue;
+            }
+            return StringPropertyReplacer.replaceProperties(n.getTextValue());
+        }
+
+        @Override
+        public Integer getInt(String key) {
+            return getInt(key, null);
+        }
+
+        @Override
+        public Integer getInt(String key, Integer defaultValue) {
+            if (config == null) {
+                return defaultValue;
+            }
+            JsonNode n = config.get(key);
+            if (n == null) {
+                return defaultValue;
+            }
+            if (n.isTextual()) {
+                return Integer.parseInt(StringPropertyReplacer.replaceProperties(n.getTextValue()));
+            } else {
+                return n.getIntValue();
+            }
+        }
+
+        @Override
+        public Long getLong(String key) {
+            return getLong(key, null);
+        }
+
+        @Override
+        public Long getLong(String key, Long defaultValue) {
+            if (config == null) {
+                return defaultValue;
+            }
+            JsonNode n = config.get(key);
+            if (n == null) {
+                return defaultValue;
+            }
+            if (n.isTextual()) {
+                return Long.parseLong(StringPropertyReplacer.replaceProperties(n.getTextValue()));
+            } else {
+                return n.getLongValue();
+            }
+        }
+
+        @Override
+        public Boolean getBoolean(String key) {
+            return getBoolean(key, null);
+        }
+
+        @Override
+        public Boolean getBoolean(String key, Boolean defaultValue) {
+            if (config == null) {
+                return defaultValue;
+            }
+            JsonNode n = config.get(key);
+            if (n == null) {
+                return defaultValue;
+            }
+            if (n.isTextual()) {
+                return Boolean.parseBoolean(StringPropertyReplacer.replaceProperties(n.getTextValue()));
+            } else {
+                return n.getBooleanValue();
+            }
+        }
+    }
+
+}
diff --git a/social/core/src/main/java/org/keycloak/social/SocialLoader.java b/social/core/src/main/java/org/keycloak/social/SocialLoader.java
index 6d24535..23876e1 100644
--- a/social/core/src/main/java/org/keycloak/social/SocialLoader.java
+++ b/social/core/src/main/java/org/keycloak/social/SocialLoader.java
@@ -2,8 +2,6 @@ package org.keycloak.social;
 
 import org.keycloak.util.ProviderLoader;
 
-import java.util.ServiceLoader;
-
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
diff --git a/social/core/src/main/test/java/org/keycloak/social/utils/SimpleHttpTest.java b/social/core/src/main/test/java/org/keycloak/social/utils/SimpleHttpTest.java
index 6f3103d..e901be7 100644
--- a/social/core/src/main/test/java/org/keycloak/social/utils/SimpleHttpTest.java
+++ b/social/core/src/main/test/java/org/keycloak/social/utils/SimpleHttpTest.java
@@ -90,10 +90,9 @@ public class SimpleHttpTest {
 
     @Test
     public void testGetCustomHeader() throws IOException {
-        JsonNode o = SimpleHttp.doGet("http://localhost:8081/tojson").header("Accept", "application/json").header("Authorization", "bearer dsfsadfsdf").asJson();
+        JsonNode o = SimpleHttp.doGet("http://localhost:8081/tojson").header("Authorization", "bearer dsfsadfsdf").asJson();
         JsonNode h = o.get("headers");
 
-        assertEquals("application/json", h.get("Accept"));
         assertEquals("bearer dsfsadfsdf", h.get("Authorization").getTextValue());
     }
 
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 74c30bb..f54b269 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -430,10 +430,10 @@
             </activation>
 
             <properties>
-                <keycloak.mongo.host>localhost</keycloak.mongo.host>
-                <keycloak.mongo.port>27018</keycloak.mongo.port>
-                <keycloak.mongo.db>keycloak</keycloak.mongo.db>
-                <keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
+                <keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
+                <keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
+                <keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
+                <keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
             </properties>
 
             <build>
@@ -452,16 +452,17 @@
                                 </goals>
                                 <configuration>
                                     <systemPropertyVariables>
-                                        <keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
-                                        <keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
-                                        <keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
+                                        <keycloak.model.provider>mongo</keycloak.model.provider>
+                                        <keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
+                                        <keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
+                                        <keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
 
-                                        <keycloak.audit>mongo</keycloak.audit>
-                                        <keycloak.audit.mongo.host>${keycloak.mongo.host}</keycloak.audit.mongo.host>
-                                        <keycloak.audit.mongo.port>${keycloak.mongo.port}</keycloak.audit.mongo.port>
-                                        <keycloak.audit.mongo.db>${keycloak.mongo.db}</keycloak.audit.mongo.db>
+                                        <keycloak.audit.provider>mongo</keycloak.audit.provider>
+                                        <keycloak.audit.mongo.host>${keycloak.model.mongo.host}</keycloak.audit.mongo.host>
+                                        <keycloak.audit.mongo.port>${keycloak.model.mongo.port}</keycloak.audit.mongo.port>
+                                        <keycloak.audit.mongo.db>${keycloak.model.mongo.db}</keycloak.audit.mongo.db>
 
-                                        <keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
+                                        <keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
                                     </systemPropertyVariables>
                                 </configuration>
                             </execution>
@@ -486,7 +487,7 @@
                                     <goal>start</goal>
                                 </goals>
                                 <configuration>
-                                    <port>${keycloak.mongo.port}</port>
+                                    <port>${keycloak.model.mongo.port}</port>
                                     <logging>file</logging>
                                     <logFile>${project.build.directory}/mongodb.log</logFile>
                                 </configuration>
diff --git a/testsuite/integration/README.md b/testsuite/integration/README.md
index 1b3ed3e..003c215 100644
--- a/testsuite/integration/README.md
+++ b/testsuite/integration/README.md
@@ -11,7 +11,7 @@ To run the tests with Firefox add `-Dbrowser=firefox` or for Chrome add `-Dbrows
 Mongo
 -----
 
-The testsuite is executed with JPA model implementation with data saved in H2 database by default. To run testsuite with Mongo model, just add property `-Dkeycloak.model=mongo` when executing it.
+The testsuite is executed with JPA model implementation with data saved in H2 database by default. To run testsuite with Mongo model, just add property `-Dkeycloak.model.provider=mongo` when executing it.
 
 Note that this will automatically run embedded Mongo database on localhost/27018 and it will stop it after whole testsuite is finished.
 So you don't need to have Mongo installed on your laptop to run mongo execution tests.
@@ -52,11 +52,11 @@ For example to use the example themes run the server with:
 
 To start a Keycloak server with identity model data persisted in Mongo database instead of default JPA/H2 you can run:
 
-    mvn exec:java -Pkeycloak-server -Dkeycloak.model=mongo
+    mvn exec:java -Pkeycloak-server -Dkeycloak.model.provider=mongo
 
 By default it's using database `keycloak` on localhost/27017 and it uses already existing data from this DB (no cleanup of existing data during bootstrap). Assumption is that you already have DB running on localhost/27017 . Use system properties to configure things differently:
 
-    mvn exec:java -Pkeycloak-server -Dkeycloak.model=mongo -Dkeycloak.mongo.host=localhost -Dkeycloak.mongo.port=27017 -Dkeycloak.mongo.db=keycloak -Dkeycloak.mongo.clearCollectionsOnStartup=false
+    mvn exec:java -Pkeycloak-server -Dkeycloak.model.provider=mongo -Dkeycloak.model.mongo.host=localhost -Dkeycloak.model.mongo.port=27017 -Dkeycloak.model.mongo.db=keycloak -Dkeycloak.model.mongo.clearOnStartup=false
 
 TOTP codes
 ----------
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
index f3eb078..da3dc68 100755
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
@@ -30,18 +30,16 @@ import io.undertow.servlet.api.FilterInfo;
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
 import org.jboss.resteasy.spi.ResteasyDeployment;
-import org.keycloak.models.Config;
 import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.provider.ProviderSession;
 import org.keycloak.provider.ProviderSessionFactory;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.filters.ClientConnectionFilter;
 import org.keycloak.services.filters.KeycloakSessionServletFilter;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.KeycloakApplication;
-import org.keycloak.theme.DefaultKeycloakThemeProvider;
 import org.keycloak.util.JsonSerialization;
 
 import javax.servlet.DispatcherType;
@@ -129,9 +127,8 @@ public class KeycloakServer {
                 throw new RuntimeException("Invalid resources directory");
             }
 
-            if (Config.getThemeDir() == null) {
-                System.setProperty(DefaultKeycloakThemeProvider.class.getName() + ".disabled", "");
-                Config.setThemeDir(file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
+            if (!System.getProperties().containsKey("keycloak.theme.dir")) {
+                System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
             }
 
             config.setResourcesHome(dir.getAbsolutePath());
@@ -162,8 +159,6 @@ public class KeycloakServer {
 
     private KeycloakServerConfig config;
 
-    private KeycloakSessionFactory factory;
-
     private ProviderSessionFactory providerSessionFactory;
 
     private UndertowJaxrsServer server;
@@ -176,10 +171,6 @@ public class KeycloakServer {
         this.config = config;
     }
 
-    public KeycloakSessionFactory getKeycloakSessionFactory() {
-        return factory;
-    }
-
     public ProviderSessionFactory getProviderSessionFactory() {
         return providerSessionFactory;
     }
@@ -194,7 +185,8 @@ public class KeycloakServer {
     }
 
     public void importRealm(RealmRepresentation rep) {
-        KeycloakSession session = factory.createSession();
+        ProviderSession providerSession = providerSessionFactory.createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         session.getTransaction().begin();
 
         try {
@@ -217,12 +209,13 @@ public class KeycloakServer {
 
             session.getTransaction().commit();
         } finally {
-            session.close();
+            providerSession.close();
         }
     }
 
     protected void setupDevConfig() {
-        KeycloakSession session = factory.createSession();
+        ProviderSession providerSession = providerSessionFactory.createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         session.getTransaction().begin();
 
         try {
@@ -234,7 +227,7 @@ public class KeycloakServer {
 
             session.getTransaction().commit();
         } finally {
-            session.close();
+            providerSession.close();
         }
     }
 
@@ -266,7 +259,6 @@ public class KeycloakServer {
 
         server.deploy(di);
 
-        factory = ((KeycloakApplication) deployment.getApplication()).getFactory();
         providerSessionFactory = ((KeycloakApplication) deployment.getApplication()).getProviderSessionFactory();
 
         setupDevConfig();
@@ -289,7 +281,6 @@ public class KeycloakServer {
 
     public void stop() {
         providerSessionFactory.close();
-        factory.close();
         server.stop();
 
         info("Stopped Keycloak");
diff --git a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json
new file mode 100644
index 0000000..ee6c8fc
--- /dev/null
+++ b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json
@@ -0,0 +1,26 @@
+{
+    "admin": {
+        "realm": "keycloak-admin"
+    },
+
+    "audit": {
+        "provider": "${keycloak.audit.provider:jpa}"
+    },
+
+    "model": {
+        "provider": "${keycloak.model.provider:jpa}"
+    },
+
+    "timer": {
+        "provider": "basic"
+    },
+
+    "theme": {
+        "default": "keycloak",
+        "dir": "${keycloak.theme.dir}"
+    },
+
+    "scheduled": {
+        "interval": 900
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 8290d3f..393c3f7 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -22,18 +22,14 @@
 package org.keycloak.testsuite.account;
 
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.audit.Details;
 import org.keycloak.audit.Event;
-import org.keycloak.audit.jpa.JpaAuditProviderFactory;
 import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.Config;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserCredentialModel;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index ba5aaab..4051a6e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -32,6 +32,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.provider.ProviderSession;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.adapters.action.SessionStats;
 import org.keycloak.representations.idm.RealmRepresentation;
@@ -171,11 +172,11 @@ public class AdapterTest {
         System.out.println(pageSource);
         Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
 
-        KeycloakSession session = keycloakRule.startSession();
-        RealmModel realm = session.getRealmByName("demo");
+        ProviderSession providerSession = keycloakRule.startSession();
+        RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
         int originalIdle = realm.getSsoSessionIdleTimeout();
         realm.setSsoSessionIdleTimeout(1);
-        keycloakRule.stopSession(session, true);
+        keycloakRule.stopSession(providerSession, true);
 
         Thread.sleep(2000);
 
@@ -184,10 +185,10 @@ public class AdapterTest {
         driver.navigate().to("http://localhost:8081/product-portal");
         Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
 
-        session = keycloakRule.startSession();
-        realm = session.getRealmByName("demo");
+        providerSession = keycloakRule.startSession();
+        realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
         realm.setSsoSessionIdleTimeout(originalIdle);
-        keycloakRule.stopSession(session, true);
+        keycloakRule.stopSession(providerSession, true);
     }
     @Test
     public void testLoginSSOMax() throws Exception {
@@ -202,11 +203,11 @@ public class AdapterTest {
         System.out.println(pageSource);
         Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
 
-        KeycloakSession session = keycloakRule.startSession();
-        RealmModel realm = session.getRealmByName("demo");
+        ProviderSession providerSession = keycloakRule.startSession();
+        RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
         int original = realm.getSsoSessionMaxLifespan();
         realm.setSsoSessionMaxLifespan(1);
-        keycloakRule.stopSession(session, true);
+        keycloakRule.stopSession(providerSession, true);
 
         Thread.sleep(2000);
 
@@ -215,9 +216,9 @@ public class AdapterTest {
         driver.navigate().to("http://localhost:8081/product-portal");
         Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
 
-        session = keycloakRule.startSession();
-        realm = session.getRealmByName("demo");
+        providerSession = keycloakRule.startSession();
+        realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
         realm.setSsoSessionMaxLifespan(original);
-        keycloakRule.stopSession(session, true);
+        keycloakRule.stopSession(providerSession, true);
     }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index a57aff1..4a8543e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -4,10 +4,10 @@ import org.hamcrest.CoreMatchers;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
-import org.jboss.logging.Logger;
 import org.junit.Assert;
 import org.junit.rules.TestRule;
 import org.junit.runners.model.Statement;
+import org.keycloak.Config;
 import org.keycloak.audit.AuditListener;
 import org.keycloak.audit.AuditListenerFactory;
 import org.keycloak.audit.Details;
@@ -59,11 +59,6 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
     }
 
     @Override
-    public boolean lazyLoad() {
-        return false;
-    }
-
-    @Override
     public Statement apply(final Statement base, org.junit.runner.Description description) {
         return new Statement() {
             @Override
@@ -194,7 +189,7 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
     }
 
     @Override
-    public void init() {
+    public void init(Config.Scope config) {
     }
 
     @Override
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
index cead905..4b1645e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
@@ -29,14 +29,12 @@ import org.keycloak.OAuth2Constants;
 import org.keycloak.audit.Details;
 import org.keycloak.audit.Errors;
 import org.keycloak.audit.Event;
-import org.keycloak.models.Config;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.provider.ProviderSession;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.RefreshToken;
-import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
@@ -47,7 +45,11 @@ import org.keycloak.testsuite.rule.WebRule;
 import org.keycloak.util.Time;
 import org.openqa.selenium.WebDriver;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThan;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
@@ -181,8 +183,8 @@ public class RefreshTokenTest {
 
         String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
 
-        KeycloakSession session = keycloakRule.startSession();
-        RealmModel realm = session.getRealmByName("test");
+        ProviderSession session = keycloakRule.startSession();
+        RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         UserSessionModel userSession = realm.getUserSession(sessionId);
         int last = userSession.getLastSessionRefresh();
         keycloakRule.stopSession(session, false);
@@ -197,7 +199,7 @@ public class RefreshTokenTest {
         Assert.assertEquals(200, tokenResponse.getStatusCode());
 
         session = keycloakRule.startSession();
-        realm = session.getRealmByName("test");
+        realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         userSession = realm.getUserSession(sessionId);
         int next = userSession.getLastSessionRefresh();
         keycloakRule.stopSession(session, false);
@@ -208,7 +210,7 @@ public class RefreshTokenTest {
 
 
         session = keycloakRule.startSession();
-        realm = session.getRealmByName("test");
+        realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         int lastAccessTokenLifespan = realm.getAccessTokenLifespan();
         realm.setAccessTokenLifespan(100000);
         keycloakRule.stopSession(session, true);
@@ -217,7 +219,7 @@ public class RefreshTokenTest {
         tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
 
         session = keycloakRule.startSession();
-        realm = session.getRealmByName("test");
+        realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         userSession = realm.getUserSession(sessionId);
         next = userSession.getLastSessionRefresh();
         keycloakRule.stopSession(session, false);
@@ -226,7 +228,7 @@ public class RefreshTokenTest {
         Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 6)));
 
         session = keycloakRule.startSession();
-        realm = session.getRealmByName("test");
+        realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         int originalIdle = realm.getSsoSessionIdleTimeout();
         realm.setSsoSessionIdleTimeout(1);
         keycloakRule.stopSession(session, true);
@@ -243,7 +245,7 @@ public class RefreshTokenTest {
         events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
 
         session = keycloakRule.startSession();
-        realm = session.getRealmByName("test");
+        realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         realm.setSsoSessionIdleTimeout(originalIdle);
         realm.setAccessTokenLifespan(lastAccessTokenLifespan);
         keycloakRule.stopSession(session, true);
@@ -266,8 +268,8 @@ public class RefreshTokenTest {
 
         String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
 
-        KeycloakSession session = keycloakRule.startSession();
-        RealmModel realm = session.getRealmByName("test");
+        ProviderSession session = keycloakRule.startSession();
+        RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         int maxLifespan = realm.getSsoSessionMaxLifespan();
         realm.setSsoSessionMaxLifespan(1);
         keycloakRule.stopSession(session, true);
@@ -281,7 +283,7 @@ public class RefreshTokenTest {
         assertNull(tokenResponse.getRefreshToken());
 
         session = keycloakRule.startSession();
-        realm = session.getRealmByName("test");
+        realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
         realm.setSsoSessionMaxLifespan(maxLifespan);
         keycloakRule.stopSession(session, true);
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
index 9312eee..47e91ec 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
@@ -6,10 +6,11 @@ import io.undertow.servlet.api.SecurityConstraint;
 import io.undertow.servlet.api.ServletInfo;
 import io.undertow.servlet.api.WebResourceCollection;
 import org.junit.rules.ExternalResource;
-import org.keycloak.models.Config;
+import org.keycloak.Config;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.provider.ProviderSession;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.ModelToRepresentation;
@@ -33,31 +34,33 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
         server = new KeycloakServer();
         server.start();
 
-
         setupKeycloak();
     }
 
     public UserRepresentation getUser(String realm, String name) {
-        KeycloakSession session = server.getKeycloakSessionFactory().createSession();
+        ProviderSession providerSession = server.getProviderSessionFactory().createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         try {
             UserModel user = session.getRealmByName(realm).getUser(name);
             return user != null ? ModelToRepresentation.toRepresentation(user) : null;
         } finally {
-            session.close();
+            providerSession.close();
         }
     }
 
     public UserRepresentation getUserById(String realm, String id) {
-        KeycloakSession session = server.getKeycloakSessionFactory().createSession();
+        ProviderSession providerSession = server.getProviderSessionFactory().createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         try {
             return ModelToRepresentation.toRepresentation(session.getRealmByName(realm).getUserById(id));
         } finally {
-            session.close();
+            providerSession.close();
         }
     }
 
     protected void setupKeycloak() {
-        KeycloakSession session = server.getKeycloakSessionFactory().createSession();
+        ProviderSession providerSession = server.getProviderSessionFactory().createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         session.getTransaction().begin();
 
         try {
@@ -69,9 +72,8 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
             session.getTransaction().commit();
         } finally {
-            session.close();
+            providerSession.close();
         }
-
     }
 
     protected void configure(RealmManager manager, RealmModel adminRealm) {
@@ -134,15 +136,16 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
         return JsonSerialization.readValue(bytes, RealmRepresentation.class);
     }
 
-    public KeycloakSession startSession() {
-        KeycloakSession session = server.getKeycloakSessionFactory().createSession();
+    public ProviderSession startSession() {
+        ProviderSession providerSession = server.getProviderSessionFactory().createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         session.getTransaction().begin();
-        return session;
+        return providerSession;
     }
 
-    public void stopSession(KeycloakSession session, boolean commit) {
+    public void stopSession(ProviderSession session, boolean commit) {
         if (commit) {
-            session.getTransaction().commit();
+            session.getProvider(KeycloakSession.class).getTransaction().commit();
         }
         session.close();
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
index 4096658..f520d19 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
@@ -21,7 +21,7 @@
  */
 package org.keycloak.testsuite.rule;
 
-import org.keycloak.models.Config;
+import org.keycloak.Config;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
@@ -61,8 +61,8 @@ public class KeycloakRule extends AbstractKeycloakRule {
     }
 
     public void configure(KeycloakSetup configurer) {
-        KeycloakSession session = server.getKeycloakSessionFactory().createSession();
         ProviderSession providerSession = server.getProviderSessionFactory().createSession();
+        KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
         session.getTransaction().begin();
 
         try {
@@ -77,17 +77,16 @@ public class KeycloakRule extends AbstractKeycloakRule {
             session.getTransaction().commit();
         } finally {
             providerSession.close();
-            session.close();
         }
     }
 
     public void removeUserSession(String sessionId) {
-        KeycloakSession keycloakSession = startSession();
-        RealmModel realm = keycloakSession.getRealm("test");
+        ProviderSession providerSession = startSession();
+        RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealm("test");
         UserSessionModel session = realm.getUserSession(sessionId);
         assertNotNull(session);
         realm.removeUserSession(session);
-        stopSession(keycloakSession, true);
+        stopSession(providerSession, true);
     }
 
     public abstract static class KeycloakSetup {
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java
index eda2761..c78cb61 100755
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java
@@ -6,6 +6,8 @@ import org.apache.jmeter.samplers.SampleResult;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.provider.ProviderSession;
+import org.keycloak.provider.ProviderSessionFactory;
 import org.keycloak.services.resources.KeycloakApplication;
 
 import java.util.concurrent.Callable;
@@ -18,17 +20,17 @@ import java.util.concurrent.atomic.AtomicInteger;
 public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
 
 
-    private static FutureTask<KeycloakSessionFactory> factoryProvider = new FutureTask<KeycloakSessionFactory>(new Callable() {
+    private static FutureTask<ProviderSessionFactory> factoryProvider = new FutureTask<ProviderSessionFactory>(new Callable() {
 
         @Override
-        public KeycloakSessionFactory call() throws Exception {
-            return KeycloakApplication.createSessionFactory();
+        public ProviderSessionFactory call() throws Exception {
+            return KeycloakApplication.createProviderSessionFactory();
         }
 
     });
     private static AtomicInteger counter = new AtomicInteger();
 
-    private KeycloakSessionFactory factory;
+    private ProviderSessionFactory factory;
     // private KeycloakSession identitySession;
     private Worker worker;
     private boolean setupSuccess = false;
@@ -42,7 +44,8 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
         worker = getWorker();
 
         factory = getFactory();
-        KeycloakSession identitySession = factory.createSession();
+        ProviderSession providerSession = factory.createSession();
+        KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
         KeycloakTransaction transaction = identitySession.getTransaction();
         transaction.begin();
 
@@ -56,11 +59,11 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
             } else {
                 transaction.rollback();
             }
-            identitySession.close();
+            providerSession.close();
         }
     }
 
-    private static KeycloakSessionFactory getFactory() {
+    private static ProviderSessionFactory getFactory() {
         factoryProvider.run();
         try {
             return factoryProvider.get();
@@ -98,7 +101,8 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
             return result;
         }
 
-        KeycloakSession identitySession = factory.createSession();
+        ProviderSession providerSession = factory.createSession();
+        KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
         KeycloakTransaction transaction = identitySession.getTransaction();
         try {
             transaction.begin();
@@ -114,7 +118,7 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
         } finally {
             result.sampleEnd();
             result.setSuccessful(true);
-            identitySession.close();
+            providerSession.close();
         }
 
         return result;
diff --git a/testsuite/performance/src/test/jmeter/system.properties b/testsuite/performance/src/test/jmeter/system.properties
index 26d24aa..c1cdda4 100644
--- a/testsuite/performance/src/test/jmeter/system.properties
+++ b/testsuite/performance/src/test/jmeter/system.properties
@@ -8,11 +8,11 @@ keycloak.jpa.hbm2ddl.auto=create
 
 
 ## Configure MongoDB (Useful just when keycloak.sessionFactory=mongo)
-keycloak.mongodb.host=localhost
-keycloak.mongodb.port=27017
-keycloak.mongodb.databaseName=keycloakPerfTest
+keycloak.model.mongo.host=localhost
+keycloak.model.mongo.port=27017
+keycloak.model.mongo.databaseName=keycloakPerfTest
 # Should be DB dropped at startup of the test?
-keycloak.mongodb.dropDatabaseOnStartup=true
+keycloak.model.mongo.dropDatabaseOnStartup=true
 
 
 ## Specify Keycloak worker class
diff --git a/timer/api/src/main/java/org/keycloak/timer/TimerProvider.java b/timer/api/src/main/java/org/keycloak/timer/TimerProvider.java
index e701b5f..627f00e 100644
--- a/timer/api/src/main/java/org/keycloak/timer/TimerProvider.java
+++ b/timer/api/src/main/java/org/keycloak/timer/TimerProvider.java
@@ -7,6 +7,6 @@ import org.keycloak.provider.Provider;
  */
 public interface TimerProvider extends Provider {
 
-    public void schedule(Runnable runnable, String config);
+    public void schedule(Runnable runnable, long interval);
 
 }
diff --git a/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java b/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
new file mode 100644
index 0000000..d0e57f9
--- /dev/null
+++ b/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
@@ -0,0 +1,25 @@
+package org.keycloak.timer;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class TimerSpi implements Spi {
+    @Override
+    public String getName() {
+        return "timer";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return TimerProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return TimerProviderFactory.class;
+    }
+}
diff --git a/timer/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/timer/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000..e8219ff
--- /dev/null
+++ b/timer/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1 @@
+org.keycloak.timer.TimerSpi
\ No newline at end of file
diff --git a/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProvider.java b/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProvider.java
index bda150b..267f17c 100644
--- a/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProvider.java
+++ b/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProvider.java
@@ -18,9 +18,7 @@ public class BasicTimerProvider implements TimerProvider {
     }
 
     @Override
-    public void schedule(final Runnable runnable, String config) {
-        long interval = Long.parseLong(config);
-
+    public void schedule(final Runnable runnable, final long interval) {
         TimerTask task = new TimerTask() {
             @Override
             public void run() {
diff --git a/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProviderFactory.java b/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProviderFactory.java
index 466167d..3454d87 100644
--- a/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProviderFactory.java
+++ b/timer/basic/src/main/java/org/keycloak/timer/basic/BasicTimerProviderFactory.java
@@ -1,5 +1,6 @@
 package org.keycloak.timer.basic;
 
+import org.keycloak.Config;
 import org.keycloak.provider.ProviderSession;
 import org.keycloak.timer.TimerProvider;
 import org.keycloak.timer.TimerProviderFactory;
@@ -19,7 +20,7 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
     }
 
     @Override
-    public void init() {
+    public void init(Config.Scope config) {
         timer = new Timer();
     }
 
@@ -34,8 +35,4 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
         return "basic";
     }
 
-    @Override
-    public boolean lazyLoad() {
-        return true;
-    }
 }