keycloak-uncached

Details

diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
index 1795cd1..aac1cde 100755
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
@@ -1,19 +1,5 @@
 package org.keycloak.connections.jpa;
 
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.naming.InitialContext;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.Persistence;
-import javax.sql.DataSource;
-
 import org.hibernate.ejb.AvailableSettings;
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
@@ -22,215 +8,232 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.provider.ProviderOperationalInfo;
 
+import javax.naming.InitialContext;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.sql.DataSource;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory {
 
-	private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class);
-
-	private volatile EntityManagerFactory emf;
-
-	private Config.Scope config;
-
-	private DatabaseInfo databaseInfo;
-
-	@Override
-	public JpaConnectionProvider create(KeycloakSession session) {
-		lazyInit(session);
-
-		EntityManager em = emf.createEntityManager();
-		em = PersistenceExceptionConverter.create(em);
-		session.getTransaction().enlist(new JpaKeycloakTransaction(em));
-		return new DefaultJpaConnectionProvider(em);
-	}
-
-	@Override
-	public void close() {
-		if (emf != null) {
-			emf.close();
-		}
-	}
-
-	@Override
-	public String getId() {
-		return "default";
-	}
-
-	@Override
-	public void init(Config.Scope config) {
-		this.config = config;
-	}
-
-	@Override
-	public void postInit(KeycloakSessionFactory factory) {
-
-	}
-
-	private void lazyInit(KeycloakSession session) {
-		if (emf == null) {
-			synchronized (this) {
-				if (emf == null) {
-					logger.debug("Initializing JPA connections");
-
-					Connection connection = null;
-
-					String databaseSchema = config.get("databaseSchema");
-
-					Map<String, Object> properties = new HashMap<String, Object>();
-
-					String unitName = "keycloak-default";
-
-					String dataSource = config.get("dataSource");
-					if (dataSource != null) {
-						if (config.getBoolean("jta", false)) {
-							properties.put(AvailableSettings.JTA_DATASOURCE, dataSource);
-						} else {
-							properties.put(AvailableSettings.NON_JTA_DATASOURCE, dataSource);
-						}
-					} else {
-						properties.put(AvailableSettings.JDBC_URL, config.get("url"));
-						properties.put(AvailableSettings.JDBC_DRIVER, config.get("driver"));
-
-						String user = config.get("user");
-						if (user != null) {
-							properties.put(AvailableSettings.JDBC_USER, user);
-						}
-						String password = config.get("password");
-						if (password != null) {
-							properties.put(AvailableSettings.JDBC_PASSWORD, password);
-						}
-					}
-
-					String driverDialect = config.get("driverDialect");
-					if (driverDialect != null && driverDialect.length() > 0) {
-						properties.put("hibernate.dialect", driverDialect);
-					}
-
-					String schema = config.get("schema");
-					if (schema != null) {
-						properties.put("hibernate.default_schema", schema);
-					}
-
-					if (databaseSchema != null) {
-						if (databaseSchema.equals("development-update")) {
-							properties.put("hibernate.hbm2ddl.auto", "update");
-							databaseSchema = null;
-						} else if (databaseSchema.equals("development-validate")) {
-							properties.put("hibernate.hbm2ddl.auto", "validate");
-							databaseSchema = null;
-						}
-					}
-
-					properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
-					properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
-
-					connection = getConnection();
-					prepareDatabaseInfo(connection);
-
-					if (databaseSchema != null) {
-						logger.trace("Updating database");
-
-						JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class);
-						if (updater == null) {
-							throw new RuntimeException("Can't update database: JPA updater provider not found");
-						}
-
-						if (databaseSchema.equals("update")) {
-							String currentVersion = null;
-							try {
-								ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql(schema));
-								if (resultSet.next()) {
-									currentVersion = resultSet.getString(1);
-								}
-							} catch (SQLException e) {
-							}
-
-							if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
-								updater.update(session, connection, schema);
-							} else {
-								logger.debug("Database is up to date");
-							}
-						} else if (databaseSchema.equals("validate")) {
-							updater.validate(connection, schema);
-						} else {
-							throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
-						}
-
-						logger.trace("Database update completed");
-					}
-
-					logger.trace("Creating EntityManagerFactory");
-					emf = Persistence.createEntityManagerFactory(unitName, properties);
-					logger.trace("EntityManagerFactory created");
-
-					// Close after creating EntityManagerFactory to prevent in-mem databases from closing
-					if (connection != null) {
-						try {
-							connection.close();
-						} catch (SQLException e) {
-							logger.warn(e);
-						}
-					}
-				}
-			}
-		}
-	}
-
-	protected void prepareDatabaseInfo(Connection connection) {
-		try {
-			databaseInfo = new DatabaseInfo();
-			DatabaseMetaData md = connection.getMetaData();
-			databaseInfo.databaseDriver = md.getDriverName() + " " + md.getDriverVersion();
-			databaseInfo.databaseProduct = md.getDatabaseProductName() + " " + md.getDatabaseProductVersion();
-			databaseInfo.databaseUser = md.getUserName();
-			databaseInfo.jdbcUrl = md.getURL();
-		} catch (SQLException e) {
-			logger.warn("Unable to get database info due " + e.getMessage());
-		}
-	}
-
-	private Connection getConnection() {
-		try {
-			String dataSourceLookup = config.get("dataSource");
-			if (dataSourceLookup != null) {
-				DataSource dataSource = (DataSource) new InitialContext().lookup(dataSourceLookup);
-				return dataSource.getConnection();
-			} else {
-				Class.forName(config.get("driver"));
-				return DriverManager.getConnection(config.get("url"), config.get("user"), config.get("password"));
-			}
-		} catch (Exception e) {
-			throw new RuntimeException("Failed to connect to database", e);
-		}
-	}
-
-	@Override
-	public DatabaseInfo getOperationalInfo() {
-		return databaseInfo;
-	}
-
-	public static class DatabaseInfo implements ProviderOperationalInfo {
-		protected String jdbcUrl;
-		protected String databaseUser;
-		protected String databaseProduct;
-		protected String databaseDriver;
-
-		public String getJdbcUrl() {
-			return jdbcUrl;
-		}
-
-		public String getDatabaseDriver() {
-			return databaseDriver;
-		}
-
-		public String getDatabaseUser() {
-			return databaseUser;
-		}
-
-		public String getDatabaseProduct() {
-			return databaseProduct;
-		}
-	}
+    private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class);
+
+    private volatile EntityManagerFactory emf;
+
+    private Config.Scope config;
+    
+    private DatabaseInfo databaseInfo;
+
+    @Override
+    public JpaConnectionProvider create(KeycloakSession session) {
+        lazyInit(session);
+
+        EntityManager em = emf.createEntityManager();
+        em = PersistenceExceptionConverter.create(em);
+        session.getTransaction().enlist(new JpaKeycloakTransaction(em));
+        return new DefaultJpaConnectionProvider(em);
+    }
+
+    @Override
+    public void close() {
+        if (emf != null) {
+            emf.close();
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "default";
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        this.config = config;
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    private void lazyInit(KeycloakSession session) {
+        if (emf == null) {
+            synchronized (this) {
+                if (emf == null) {
+                    logger.debug("Initializing JPA connections");
+
+                    Connection connection = null;
+
+                    String databaseSchema = config.get("databaseSchema");
+
+                    Map<String, Object> properties = new HashMap<String, Object>();
+
+                    String unitName = "keycloak-default";
+
+                    String dataSource = config.get("dataSource");
+                    if (dataSource != null) {
+                        if (config.getBoolean("jta", false)) {
+                            properties.put(AvailableSettings.JTA_DATASOURCE, dataSource);
+                        } else {
+                            properties.put(AvailableSettings.NON_JTA_DATASOURCE, dataSource);
+                        }
+                    } else {
+                        properties.put(AvailableSettings.JDBC_URL, config.get("url"));
+                        properties.put(AvailableSettings.JDBC_DRIVER, config.get("driver"));
+
+                        String user = config.get("user");
+                        if (user != null) {
+                            properties.put(AvailableSettings.JDBC_USER, user);
+                        }
+                        String password = config.get("password");
+                        if (password != null) {
+                            properties.put(AvailableSettings.JDBC_PASSWORD, password);
+                        }
+                    }
+
+                    String driverDialect = config.get("driverDialect");
+                    if (driverDialect != null && driverDialect.length() > 0) {
+                        properties.put("hibernate.dialect", driverDialect);
+                    }
+
+                    String schema = config.get("schema");
+                    if (schema != null) {
+                        properties.put("hibernate.default_schema", schema);
+                    }
+
+                    if (databaseSchema != null) {
+                        if (databaseSchema.equals("development-update")) {
+                            properties.put("hibernate.hbm2ddl.auto", "update");
+                            databaseSchema = null;
+                        } else if (databaseSchema.equals("development-validate")) {
+                            properties.put("hibernate.hbm2ddl.auto", "validate");
+                            databaseSchema = null;
+                        }
+                    }
+
+                    properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
+                    properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
+
+                    connection = getConnection();
+                    try{ 
+	                    prepareDatabaseInfo(connection);
+	                    
+	                    if (databaseSchema != null) {
+	                        logger.trace("Updating database");
+	
+	                        JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class);
+	                        if (updater == null) {
+	                            throw new RuntimeException("Can't update database: JPA updater provider not found");
+	                        }
+	
+	                        if (databaseSchema.equals("update")) {
+	                            String currentVersion = null;
+	                            try {
+	                                ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql(schema));
+	                                if (resultSet.next()) {
+	                                    currentVersion = resultSet.getString(1);
+	                                }
+	                            } catch (SQLException e) {
+	                            }
+	
+	                            if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
+	                                updater.update(session, connection, schema);
+	                            } else {
+	                                logger.debug("Database is up to date");
+	                            }
+	                        } else if (databaseSchema.equals("validate")) {
+	                            updater.validate(connection, schema);
+	                        } else {
+	                            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+	                        }
+	
+	                        logger.trace("Database update completed");
+	                    }
+	
+	                    logger.trace("Creating EntityManagerFactory");
+	                    emf = Persistence.createEntityManagerFactory(unitName, properties);
+	                    logger.trace("EntityManagerFactory created");
+
+                    } finally {
+	                    // Close after creating EntityManagerFactory to prevent in-mem databases from closing
+	                    if (connection != null) {
+	                        try {
+	                            connection.close();
+	                        } catch (SQLException e) {
+	                            logger.warn(e);
+	                        }
+	                    }
+                    }
+                }
+            }
+        }
+    }
+    
+    protected void prepareDatabaseInfo(Connection connection) {
+  		try {
+  			databaseInfo = new DatabaseInfo();
+  			DatabaseMetaData md = connection.getMetaData();
+  			databaseInfo.databaseDriver = md.getDriverName() + " " + md.getDriverVersion();
+  			databaseInfo.databaseProduct = md.getDatabaseProductName() + " " + md.getDatabaseProductVersion();
+  			databaseInfo.databaseUser = md.getUserName();
+  			databaseInfo.jdbcUrl = md.getURL();
+  		} catch (SQLException e) {
+  			logger.warn("Unable to get database info due " + e.getMessage());
+  		}
+  	}
+
+    private Connection getConnection() {
+        try {
+            String dataSourceLookup = config.get("dataSource");
+            if (dataSourceLookup != null) {
+                DataSource dataSource = (DataSource) new InitialContext().lookup(dataSourceLookup);
+                return dataSource.getConnection();
+            } else {
+                Class.forName(config.get("driver"));
+                return DriverManager.getConnection(config.get("url"), config.get("user"), config.get("password"));
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to connect to database", e);
+        }
+    }
+    
+    @Override
+  	public DatabaseInfo getOperationalInfo() {
+  		return databaseInfo;
+  	}
+
+  	public static class DatabaseInfo implements ProviderOperationalInfo {
+  		protected String jdbcUrl;
+  		protected String databaseUser;
+  		protected String databaseProduct;
+  		protected String databaseDriver;
+
+  		public String getJdbcUrl() {
+  			return jdbcUrl;
+  		}
+
+  		public String getDatabaseDriver() {
+  			return databaseDriver;
+  		}
+
+  		public String getDatabaseUser() {
+  			return databaseUser;
+  		}
+
+  		public String getDatabaseProduct() {
+  			return databaseProduct;
+  		}
+  	}
 
 }
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 248b880..2df4b85 100755
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -1,10 +1,10 @@
 package org.keycloak.connections.mongo;
 
-import java.lang.reflect.Method;
-import java.net.UnknownHostException;
-import java.util.Collections;
-
-import javax.net.ssl.SSLSocketFactory;
+import com.mongodb.DB;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
 
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
@@ -16,217 +16,234 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.provider.ProviderOperationalInfo;
 
-import com.mongodb.DB;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoClientOptions;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
+import javax.net.ssl.SSLSocketFactory;
+
+import java.lang.reflect.Method;
+import java.net.UnknownHostException;
+import java.util.Collections;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
 
-	// TODO Make configurable
-	private String[] entities = new String[] { "org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity", "org.keycloak.models.mongo.keycloak.entities.MongoUserEntity", "org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity",
-			"org.keycloak.models.entities.IdentityProviderEntity", "org.keycloak.models.entities.ClientIdentityProviderMappingEntity", "org.keycloak.models.entities.RequiredCredentialEntity", "org.keycloak.models.entities.CredentialEntity",
-			"org.keycloak.models.entities.FederatedIdentityEntity", "org.keycloak.models.mongo.keycloak.entities.MongoClientEntity", "org.keycloak.models.sessions.mongo.entities.MongoUsernameLoginFailureEntity",
-			"org.keycloak.models.sessions.mongo.entities.MongoUserSessionEntity", "org.keycloak.models.sessions.mongo.entities.MongoClientSessionEntity", "org.keycloak.models.entities.UserFederationProviderEntity",
-			"org.keycloak.models.entities.UserFederationMapperEntity", "org.keycloak.models.entities.ProtocolMapperEntity", "org.keycloak.models.entities.IdentityProviderMapperEntity",
-			"org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity", "org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity", "org.keycloak.models.entities.AuthenticationExecutionEntity",
-			"org.keycloak.models.entities.AuthenticationFlowEntity", "org.keycloak.models.entities.AuthenticatorConfigEntity", "org.keycloak.models.entities.RequiredActionProviderEntity", };
-
-	private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
-
-	private volatile MongoClient client;
-
-	private MongoStore mongoStore;
-	private DB db;
-	protected Config.Scope config;
-
-	private MongoDbInfo mongoDbInfo;
-
-	@Override
-	public MongoConnectionProvider create(KeycloakSession session) {
-		lazyInit(session);
-
-		TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
-		session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
-		return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext);
-	}
-
-	@Override
-	public void init(Config.Scope config) {
-		this.config = config;
-	}
-
-	@Override
-	public void postInit(KeycloakSessionFactory factory) {
-
-	}
-
-	private void lazyInit(KeycloakSession session) {
-		if (client == null) {
-			synchronized (this) {
-				if (client == null) {
-					try {
-						this.client = createMongoClient();
-
-						String dbName = config.get("db", "keycloak");
-						this.db = client.getDB(dbName);
-
-						String databaseSchema = config.get("databaseSchema");
-						if (databaseSchema != null) {
-							if (databaseSchema.equals("update")) {
-								MongoUpdaterProvider mongoUpdater = session.getProvider(MongoUpdaterProvider.class);
-
-								if (mongoUpdater == null) {
-									throw new RuntimeException("Can't update database: Mongo updater provider not found");
-								}
-
-								mongoUpdater.update(session, db);
-							} else {
-								throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
-							}
-						}
-
-						this.mongoStore = new MongoStoreImpl(db, getManagedEntities());
-					} catch (Exception e) {
-						throw new RuntimeException(e);
-					}
-				}
-			}
-		}
-	}
-
-	private Class[] getManagedEntities() throws ClassNotFoundException {
-		Class[] entityClasses = new Class[entities.length];
-		for (int i = 0; i < entities.length; i++) {
-			entityClasses[i] = Thread.currentThread().getContextClassLoader().loadClass(entities[i]);
-		}
-		return entityClasses;
-	}
-
-	@Override
-	public void close() {
-		if (client != null) {
-			client.close();
-		}
-	}
-
-	@Override
-	public String getId() {
-		return "default";
-	}
-
-	/**
-	 * Override this method if you want more possibility to configure Mongo client. It can be also used to inject mongo
-	 * client from different source.
-	 * 
-	 * This method can assume that "config" is already set and can use it.
-	 * 
-	 * @return mongoClient instance, which will be shared for whole Keycloak
-	 * 
-	 * @throws UnknownHostException
-	 */
-	protected MongoClient createMongoClient() throws UnknownHostException {
-		String host = config.get("host", ServerAddress.defaultHost());
-		int port = config.getInt("port", ServerAddress.defaultPort());
-		String dbName = config.get("db", "keycloak");
-
-		String user = config.get("user");
-		String password = config.get("password");
-
-		MongoClientOptions clientOptions = getClientOptions();
-
-		MongoClient client;
-		if (user != null && password != null) {
-			MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
-			client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential), clientOptions);
-		} else {
-			client = new MongoClient(new ServerAddress(host, port), clientOptions);
-		}
-
-		mongoDbInfo = new MongoDbInfo();
-		mongoDbInfo.driverVersion = client.getVersion();
-		mongoDbInfo.address = client.getAddress().toString();
-		mongoDbInfo.database = dbName;
-		mongoDbInfo.user = user;
-
-		logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName);
-		return client;
-	}
-
-	protected MongoClientOptions getClientOptions() {
-		MongoClientOptions.Builder builder = MongoClientOptions.builder();
-		checkIntOption("connectionsPerHost", builder);
-		checkIntOption("threadsAllowedToBlockForConnectionMultiplier", builder);
-		checkIntOption("maxWaitTime", builder);
-		checkIntOption("connectTimeout", builder);
-		checkIntOption("socketTimeout", builder);
-		checkBooleanOption("socketKeepAlive", builder);
-		checkBooleanOption("autoConnectRetry", builder);
-		if (config.getLong("maxAutoConnectRetryTime") != null) {
-			builder.maxAutoConnectRetryTime(config.getLong("maxAutoConnectRetryTime"));
-		}
-		if (config.getBoolean("ssl", false)) {
-			builder.socketFactory(SSLSocketFactory.getDefault());
-		}
-
-		return builder.build();
-	}
-
-	protected void checkBooleanOption(String optionName, MongoClientOptions.Builder builder) {
-		Boolean val = config.getBoolean(optionName);
-		if (val != null) {
-			try {
-				Method m = MongoClientOptions.Builder.class.getMethod(optionName, boolean.class);
-				m.invoke(builder, val);
-			} catch (Exception e) {
-				throw new IllegalStateException("Problem configuring boolean option " + optionName + " for mongo client. Ensure you used correct value true or false and if this option is supported by mongo driver", e);
-			}
-		}
-	}
-
-	protected void checkIntOption(String optionName, MongoClientOptions.Builder builder) {
-		Integer val = config.getInt(optionName);
-		if (val != null) {
-			try {
-				Method m = MongoClientOptions.Builder.class.getMethod(optionName, int.class);
-				m.invoke(builder, val);
-			} catch (Exception e) {
-				throw new IllegalStateException("Problem configuring int option " + optionName + " for mongo client. Ensure you used correct value (number) and if this option is supported by mongo driver", e);
-			}
-		}
-	}
-
-	@Override
-	public ProviderOperationalInfo getOperationalInfo() {
-		return mongoDbInfo;
-	}
-
-	public static class MongoDbInfo implements ProviderOperationalInfo {
-
-		public String address;
-		public String database;
-		public String driverVersion;
-		public String user;
-
-		public String getAddress() {
-			return address;
-		}
-
-		public String getDatabase() {
-			return database;
-		}
-
-		public String getDriverVersion() {
-			return driverVersion;
-		}
-
-		public String getUser() {
-			return user;
-		}
-	}
-
+    // TODO Make configurable
+    private String[] entities = new String[]{
+            "org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity",
+            "org.keycloak.models.mongo.keycloak.entities.MongoUserEntity",
+            "org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity",
+            "org.keycloak.models.entities.IdentityProviderEntity",
+            "org.keycloak.models.entities.ClientIdentityProviderMappingEntity",
+            "org.keycloak.models.entities.RequiredCredentialEntity",
+            "org.keycloak.models.entities.CredentialEntity",
+            "org.keycloak.models.entities.FederatedIdentityEntity",
+            "org.keycloak.models.mongo.keycloak.entities.MongoClientEntity",
+            "org.keycloak.models.sessions.mongo.entities.MongoUsernameLoginFailureEntity",
+            "org.keycloak.models.sessions.mongo.entities.MongoUserSessionEntity",
+            "org.keycloak.models.sessions.mongo.entities.MongoClientSessionEntity",
+            "org.keycloak.models.entities.UserFederationProviderEntity",
+            "org.keycloak.models.entities.UserFederationMapperEntity",
+            "org.keycloak.models.entities.ProtocolMapperEntity",
+            "org.keycloak.models.entities.IdentityProviderMapperEntity",
+            "org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity",
+            "org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity",
+            "org.keycloak.models.entities.AuthenticationExecutionEntity",
+            "org.keycloak.models.entities.AuthenticationFlowEntity",
+            "org.keycloak.models.entities.AuthenticatorConfigEntity",
+            "org.keycloak.models.entities.RequiredActionProviderEntity",
+    };
+
+    private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
+
+    private volatile MongoClient client;
+
+    private MongoStore mongoStore;
+    private DB db;
+    protected Config.Scope config;
+    
+    private MongoDbInfo mongoDbInfo;
+
+    @Override
+    public MongoConnectionProvider create(KeycloakSession session) {
+        lazyInit(session);
+
+        TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
+        session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
+        return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        this.config = config;
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+
+    private void lazyInit(KeycloakSession session) {
+        if (client == null) {
+            synchronized (this) {
+                if (client == null) {
+                    try {
+                        this.client = createMongoClient();
+
+                        String dbName = config.get("db", "keycloak");
+                        this.db = client.getDB(dbName);
+
+                        String databaseSchema = config.get("databaseSchema");
+                        if (databaseSchema != null) {
+                            if (databaseSchema.equals("update")) {
+                                MongoUpdaterProvider mongoUpdater = session.getProvider(MongoUpdaterProvider.class);
+
+                                if (mongoUpdater == null) {
+                                    throw new RuntimeException("Can't update database: Mongo updater provider not found");
+                                }
+
+                                mongoUpdater.update(session, db);
+                            } else {
+                                throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+                            }
+                        }
+
+                        this.mongoStore = new MongoStoreImpl(db, getManagedEntities());
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+    }
+
+    private Class[] getManagedEntities() throws ClassNotFoundException {
+       Class[] entityClasses = new Class[entities.length];
+        for (int i = 0; i < entities.length; i++) {
+            entityClasses[i] = Thread.currentThread().getContextClassLoader().loadClass(entities[i]);
+        }
+        return entityClasses;
+    }
+
+    @Override
+    public void close() {
+        if (client != null) {
+            client.close();
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "default";
+    }
+
+    /**
+     * Override this method if you want more possibility to configure Mongo client. It can be also used to inject mongo client
+     * from different source.
+     *
+     * This method can assume that "config" is already set and can use it.
+     *
+     * @return mongoClient instance, which will be shared for whole Keycloak
+     *
+     * @throws UnknownHostException
+     */
+    protected MongoClient createMongoClient() throws UnknownHostException {
+        String host = config.get("host", ServerAddress.defaultHost());
+        int port = config.getInt("port", ServerAddress.defaultPort());
+        String dbName = config.get("db", "keycloak");
+
+        String user = config.get("user");
+        String password = config.get("password");
+
+        MongoClientOptions clientOptions = getClientOptions();
+
+        MongoClient client;
+        if (user != null && password != null) {
+            MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
+            client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential), clientOptions);
+        } else {
+            client = new MongoClient(new ServerAddress(host, port), clientOptions);
+        }
+        
+        mongoDbInfo = new MongoDbInfo();
+    		mongoDbInfo.driverVersion = client.getVersion();
+    		mongoDbInfo.address = client.getAddress().toString();
+    		mongoDbInfo.database = dbName;
+    		mongoDbInfo.user = user;
+    		
+        logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName);
+        return client;
+    }
+
+    protected MongoClientOptions getClientOptions() {
+        MongoClientOptions.Builder builder = MongoClientOptions.builder();
+        checkIntOption("connectionsPerHost", builder);
+        checkIntOption("threadsAllowedToBlockForConnectionMultiplier", builder);
+        checkIntOption("maxWaitTime", builder);
+        checkIntOption("connectTimeout", builder);
+        checkIntOption("socketTimeout", builder);
+        checkBooleanOption("socketKeepAlive", builder);
+        checkBooleanOption("autoConnectRetry", builder);
+        if (config.getLong("maxAutoConnectRetryTime") != null) {
+            builder.maxAutoConnectRetryTime(config.getLong("maxAutoConnectRetryTime"));
+        }
+        if(config.getBoolean("ssl", false)) {
+            builder.socketFactory(SSLSocketFactory.getDefault());
+        }
+
+        return builder.build();
+    }
+
+    protected void checkBooleanOption(String optionName, MongoClientOptions.Builder builder) {
+        Boolean val = config.getBoolean(optionName);
+        if (val != null) {
+            try {
+                Method m = MongoClientOptions.Builder.class.getMethod(optionName, boolean.class);
+                m.invoke(builder, val);
+            } catch (Exception e) {
+                throw new IllegalStateException("Problem configuring boolean option " + optionName + " for mongo client. Ensure you used correct value true or false and if this option is supported by mongo driver", e);
+            }
+        }
+    }
+
+    protected void checkIntOption(String optionName, MongoClientOptions.Builder builder) {
+        Integer val = config.getInt(optionName);
+        if (val != null) {
+            try {
+                Method m = MongoClientOptions.Builder.class.getMethod(optionName, int.class);
+                m.invoke(builder, val);
+            } catch (Exception e) {
+                throw new IllegalStateException("Problem configuring int option " + optionName + " for mongo client. Ensure you used correct value (number) and if this option is supported by mongo driver", e);
+            }
+        }
+    }
+    
+    @Override
+  	public ProviderOperationalInfo getOperationalInfo() {
+  		return mongoDbInfo;
+  	}
+
+  	public static class MongoDbInfo implements ProviderOperationalInfo {
+
+  		public String address;
+  		public String database;
+  		public String driverVersion;
+  		public String user;
+
+  		public String getAddress() {
+  			return address;
+  		}
+
+  		public String getDatabase() {
+  			return database;
+  		}
+
+  		public String getDriverVersion() {
+  			return driverVersion;
+  		}
+
+  		public String getUser() {
+  			return user;
+  		}
+  	}
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
index dbb0ff0..3b69304 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
@@ -1,19 +1,5 @@
 package org.keycloak.services.resources.admin;
 
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.core.Context;
-
 import org.jboss.logging.Logger;
 import org.keycloak.Version;
 import org.keycloak.broker.provider.IdentityProvider;
@@ -43,6 +29,19 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
 import org.keycloak.social.SocialIdentityProvider;
 
+import javax.ws.rs.GET;
+import javax.ws.rs.core.Context;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -219,7 +218,6 @@ public class ServerInfoAdminResource {
     public static class MemoryInfo implements Serializable {
         
         protected long total;
-        
         protected long used;
         
         public MemoryInfo(){
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
index 85a81bb..2cca19a 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
@@ -21,22 +21,6 @@
  */
 package org.keycloak.testsuite.admin;
 
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.ClientRequestContext;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-
 import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
@@ -57,8 +41,23 @@ import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.admin.AdminRoot;
-import org.keycloak.testsuite.KeycloakServer;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.keycloak.testsuite.KeycloakServer;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Tests Undertow Adapter