From b51661b790eab3c7f9f2abf533b1ce6dad8c371e Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Mon, 20 Jul 2015 17:11:04 +0200 Subject: [PATCH 01/14] KEYCLOAK-1542 - added system and memory info into "System Info" page --- .../admin/resources/partials/server-info.html | 75 +++++++- .../models/KeycloakSessionFactory.java | 2 + .../DefaultKeycloakSessionFactory.java | 12 ++ .../admin/ServerInfoAdminResource.java | 173 ++++++++++++++++-- 4 files changed, 249 insertions(+), 13 deletions(-) diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index 34c9a845d3a..5590f9576e1 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -8,10 +8,81 @@ Server Time - {{serverInfo.serverTime}} (update) + {{serverInfo.serverTime}} (update) + + + Server Uptime + {{serverInfo.serverUptime}} + + + Current Working Directory + {{serverInfo.systemInfo.userDir}} + + + Java Version + {{serverInfo.systemInfo.javaVersion}} + + + Java Vendor + {{serverInfo.systemInfo.javaVendor}} + + + Java Runtime + {{serverInfo.systemInfo.javaRuntime}} + + + Java VM + {{serverInfo.systemInfo.javaVm}} + + + Java VM Version + {{serverInfo.systemInfo.javaVmVersion}} + + + Java Home + {{serverInfo.systemInfo.javaHome}} + + + User Name + {{serverInfo.systemInfo.userName}} + + + User Timezone + {{serverInfo.systemInfo.userTimezone}} + + + User Locale + {{serverInfo.systemInfo.userLocale}} + + + System Encoding + {{serverInfo.systemInfo.fileEncoding}} + + + Operating System + {{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}} + + + OS Architecture + {{serverInfo.systemInfo.osArchitecture}} - + +

Java VM Memory Statistics

+ + + + + + + + + + + + + +
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
Providers 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 cbb3da22d5f..82665508c25 100755 --- a/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java +++ b/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java @@ -18,6 +18,8 @@ public interface KeycloakSessionFactory extends ProviderEventManager { ProviderFactory getProviderFactory(Class clazz, String id); List getProviderFactories(Class clazz); + + long getServerStartupTimestamp(); void close(); } diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java index e312aa01225..c5be21be10e 100755 --- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java @@ -28,6 +28,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { private Map, Map> factoriesMap = new HashMap, Map>(); protected CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); + protected long serverStartupTimestamp; + @Override public void register(ProviderEventListener listener) { listeners.add(listener); @@ -46,6 +48,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { } public void init() { + serverStartupTimestamp = System.currentTimeMillis(); + ProviderManager pm = new ProviderManager(getClass().getClassLoader(), Config.scope().getArray("providers")); for (Spi spi : ServiceLoader.load(Spi.class, getClass().getClassLoader())) { @@ -148,4 +152,12 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { return factory.getClass().getPackage().getName().startsWith("org.keycloak"); } + /** + * @return timestamp of Keycloak server startup + */ + @Override + public long getServerStartupTimestamp() { + return serverStartupTimestamp; + } + } 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 4f1c22575b0..c600b92e4b4 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,5 +1,18 @@ package org.keycloak.services.resources.admin; +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.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; @@ -24,17 +37,6 @@ 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.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; - /** * @author Stian Thorgersen */ @@ -55,6 +57,7 @@ public class ServerInfoAdminResource { ServerInfoRepresentation info = new ServerInfoRepresentation(); info.version = Version.VERSION; info.serverTime = new Date().toString(); + info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); setSocialProviders(info); setIdentityProviders(info); setThemes(info); @@ -187,12 +190,115 @@ public class ServerInfoAdminResource { info.clientImporters.add(data); } } + + public static class MemoryInfo{ + + public long getTotal(){ + return Runtime.getRuntime().maxMemory(); + } + + public String getTotalFormated(){ + return formatMemory(getTotal()); + } + + public long getFree(){ + return getTotal() - getUsed(); + } + public String getFreeFormated(){ + return formatMemory(getFree()); + } + + public long getUsed(){ + return Runtime.getRuntime().totalMemory(); + } + + public String getUsedFormated(){ + return formatMemory(getUsed()); + } + + public long getFreePercentage(){ + return getFree()*100/getTotal(); + } + + private String formatMemory(long bytes){ + if(bytes > 1024L*1024L){ + return bytes/(1024L *1024L) + " MB"; + } else if(bytes > 1024L){ + return bytes/(1024L) + " kB"; + } else { + return bytes + " B"; + } + } + + } + + public static class SystemInfo { + public String getJavaVersion(){ + return System.getProperty("java.version"); + } + + public String getJavaVendor(){ + return System.getProperty("java.vendor"); + } + + public String getJavaVm(){ + return System.getProperty("java.vm.name"); + } + + public String getJavaVmVersion(){ + return System.getProperty("java.vm.version"); + } + + public String getJavaRuntime(){ + return System.getProperty("java.runtime.name"); + } + + public String getJavaHome(){ + return System.getProperty("java.home"); + } + + public String getOsName(){ + return System.getProperty("os.name"); + } + + public String getOsArchitecture(){ + return System.getProperty("os.arch"); + } + + public String getOsVersion(){ + return System.getProperty("os.version"); + } + + public String getFileEncoding(){ + return System.getProperty("file.encoding"); + } + + public String getUserName(){ + return System.getProperty("user.name"); + } + + public String getUserDir(){ + return System.getProperty("user.dir"); + } + + public String getUserTimezone(){ + return System.getProperty("user.timezone"); + } + + public String getUserLocale(){ + return (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + } + + } + public static class ServerInfoRepresentation { private String version; private String serverTime; + + private long serverStartupTime; private Map> themes; @@ -211,10 +317,55 @@ public class ServerInfoAdminResource { public ServerInfoRepresentation() { } + + public SystemInfo getSystemInfo(){ + return new SystemInfo(); + } + + public MemoryInfo getMemoryInfo(){ + return new MemoryInfo(); + } public String getServerTime() { return serverTime; } + + /** + * @return server startup time formatted + */ + public String getServerStartupTime() { + return (new Date(serverStartupTime)).toString(); + } + + /** + * @return server uptime in millis + */ + public long getServerUptimeMillis(){ + return System.currentTimeMillis() - serverStartupTime; + } + + /** + * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" + */ + public String getServerUptime(){ + long diffInSeconds = getServerUptimeMillis()/1000; + long diff[] = new long[] { 0, 0, 0, 0 }; + /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); + /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; + /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; + /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); + + return String.format( + "%d day%s, %d hour%s, %d minute%s, %d second%s", + diff[0], + diff[0] != 1 ? "s" : "", + diff[1], + diff[1] != 1 ? "s" : "", + diff[2], + diff[2] != 1 ? "s" : "", + diff[3], + diff[3] != 1 ? "s" : ""); + } public String getVersion() { return version; From 84e40cbc2c108aca6503563127b886c98b9fe10a Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Tue, 21 Jul 2015 16:09:47 +0200 Subject: [PATCH 02/14] KEYCLOAK-1542 - Server Info page extended by info about DB and MongoDB. Functional test for /serverinfo REST endpoint added. --- .../DefaultJpaConnectionProviderFactory.java | 341 ++++++++++------- .../jpa/JpaConnectionProviderFactory.java | 5 +- ...DefaultMongoConnectionFactoryProvider.java | 356 ++++++++++-------- .../mongo/MongoConnectionProviderFactory.java | 4 +- .../admin/resources/partials/server-info.html | 130 +++++-- .../provider/MonitorableProviderFactory.java | 18 + .../provider/ProviderOperationalInfo.java | 22 ++ services/pom.xml | 15 + .../admin/ServerInfoAdminResource.java | 154 ++++++-- .../testsuite/admin/AdminAPITest.java | 63 +++- 10 files changed, 720 insertions(+), 388 deletions(-) create mode 100644 model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java create mode 100644 model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java 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 61bbafa6bf9..36f3c09cce7 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,189 +1,242 @@ 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; import org.keycloak.connections.jpa.updater.JpaUpdaterProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; - -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.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; +import org.keycloak.provider.ProviderOperationalInfo; /** * @author Stian Thorgersen */ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory { - private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); + private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); - private volatile EntityManagerFactory emf; + private volatile EntityManagerFactory emf; - private Config.Scope config; + private Config.Scope config; - @Override - public JpaConnectionProvider create(KeycloakSession session) { - lazyInit(session); + private DatabaseInfo databaseInfo; - EntityManager em = emf.createEntityManager(); - em = PersistenceExceptionConverter.create(em); - session.getTransaction().enlist(new JpaKeycloakTransaction(em)); - return new DefaultJpaConnectionProvider(em); - } + @Override + public JpaConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @Override - public void close() { - if (emf != null) { - emf.close(); - } - } + EntityManager em = emf.createEntityManager(); + em = PersistenceExceptionConverter.create(em); + session.getTransaction().enlist(new JpaKeycloakTransaction(em)); + return new DefaultJpaConnectionProvider(em); + } - @Override - public String getId() { - return "default"; - } + @Override + public void close() { + if (emf != null) { + emf.close(); + } + } - @Override - public void init(Config.Scope config) { - this.config = config; - } + @Override + public String getId() { + return "default"; + } - @Override - public void postInit(KeycloakSessionFactory factory) { + @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; + private void lazyInit(KeycloakSession session) { + if (emf == null) { + synchronized (this) { + if (emf == null) { + logger.debug("Initializing JPA connections"); - String databaseSchema = config.get("databaseSchema"); + Connection connection = null; - Map properties = new HashMap(); + String databaseSchema = config.get("databaseSchema"); - String unitName = "keycloak-default"; + Map properties = new HashMap(); - 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 unitName = "keycloak-default"; - 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 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 driverDialect = config.get("driverDialect"); - if (driverDialect != null && driverDialect.length() > 0) { - properties.put("hibernate.dialect", driverDialect); - } + 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 schema = config.get("schema"); - if (schema != null) { - properties.put("hibernate.default_schema", schema); - } + String driverDialect = config.get("driverDialect"); + if (driverDialect != null && driverDialect.length() > 0) { + properties.put("hibernate.dialect", driverDialect); + } - 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; - } - } + String schema = config.get("schema"); + if (schema != null) { + properties.put("hibernate.default_schema", schema); + } - properties.put("hibernate.show_sql", config.getBoolean("showSql", false)); - properties.put("hibernate.format_sql", config.getBoolean("formatSql", true)); + 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; + } + } - if (databaseSchema != null) { - logger.trace("Updating database"); + properties.put("hibernate.show_sql", config.getBoolean("showSql", false)); + properties.put("hibernate.format_sql", config.getBoolean("formatSql", true)); - JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class); - if (updater == null) { - throw new RuntimeException("Can't update database: JPA updater provider not found"); - } + connection = getConnection(); + prepareDatabaseInfo(connection); - connection = getConnection(); + if (databaseSchema != null) { + logger.trace("Updating database"); - 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) { - } + JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class); + if (updater == null) { + throw new RuntimeException("Can't update database: JPA updater provider not found"); + } - 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); - } + 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) { + } - logger.trace("Database update completed"); - } + 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("Creating EntityManagerFactory"); - emf = Persistence.createEntityManagerFactory(unitName, properties); - logger.trace("EntityManagerFactory created"); + logger.trace("Database update completed"); + } - // Close after creating EntityManagerFactory to prevent in-mem databases from closing - if (connection != null) { - try { - connection.close(); - } catch (SQLException e) { - logger.warn(e); - } - } - } - } - } - } + logger.trace("Creating EntityManagerFactory"); + emf = Persistence.createEntityManagerFactory(unitName, properties); + logger.trace("EntityManagerFactory created"); - 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); - } - } + // 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; + } + + @Override + public boolean isOk() { + // TODO KEYCLOAK-1578 - implement operational monitoring of JPA DB connection + return true; + } + } } diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java index 1cf4a5f2026..ab2b119c29c 100644 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java @@ -1,9 +1,10 @@ package org.keycloak.connections.jpa; -import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.MonitorableProviderFactory; /** * @author Stian Thorgersen */ -public interface JpaConnectionProviderFactory extends ProviderFactory { +public interface JpaConnectionProviderFactory extends MonitorableProviderFactory { + } 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 36be680a668..c8d1cbaed4a 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,11 @@ package org.keycloak.connections.mongo; -import com.mongodb.DB; -import com.mongodb.MongoClient; -import com.mongodb.MongoClientOptions; -import com.mongodb.MongoCredential; -import com.mongodb.ServerAddress; +import java.lang.reflect.Method; +import java.net.UnknownHostException; +import java.util.Collections; + +import javax.net.ssl.SSLSocketFactory; + import org.jboss.logging.Logger; import org.keycloak.Config; import org.keycloak.connections.mongo.api.MongoStore; @@ -13,198 +14,225 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati import org.keycloak.connections.mongo.updater.MongoUpdaterProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.ProviderOperationalInfo; -import javax.net.ssl.SSLSocketFactory; -import java.lang.reflect.Method; -import java.net.UnknownHostException; -import java.util.Collections; +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; /** * @author Stian Thorgersen */ 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", - }; + // 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 static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class); - private volatile MongoClient client; + private volatile MongoClient client; - private MongoStore mongoStore; - private DB db; - protected Config.Scope config; + private MongoStore mongoStore; + private DB db; + protected Config.Scope config; - @Override - public MongoConnectionProvider create(KeycloakSession session) { - lazyInit(session); + private MongoDbInfo mongoDbInfo; - TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore); - session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext)); - return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext); - } + @Override + public MongoConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @Override - public void init(Config.Scope config) { - this.config = config; - } + TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore); + session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext)); + return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext); + } - @Override - public void postInit(KeycloakSessionFactory factory) { + @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(); + 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 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); + 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"); - } + 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); - } - } + 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); - } - } - } - } - } + 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; - } + 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 void close() { + if (client != null) { + client.close(); + } + } - @Override - public String getId() { - return "default"; - } + @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"); + /** + * 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"); + String user = config.get("user"); + String password = config.get("password"); - MongoClientOptions clientOptions = getClientOptions(); + 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); - } + 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); + } - logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); - return client; - } + mongoDbInfo = new MongoDbInfo(); + mongoDbInfo.driverVersion = client.getVersion(); + mongoDbInfo.address = client.getAddress().toString(); + mongoDbInfo.database = dbName; + mongoDbInfo.user = user; - 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()); - } + logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); + return client; + } - return builder.build(); - } + 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()); + } - 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); - } - } - } + return builder.build(); + } - 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); - } - } - } + 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; + + @Override + public boolean isOk() { + // TODO KEYCLOAK-1578 - implement operational monitoring of Mongo DB connection + return true; + } + + public String getAddress() { + return address; + } + + public String getDatabase() { + return database; + } + + public String getDriverVersion() { + return driverVersion; + } + + public String getUser() { + return user; + } + } } diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java index e787ce63825..3b3a00e5602 100644 --- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java +++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java @@ -1,9 +1,9 @@ package org.keycloak.connections.mongo; -import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.MonitorableProviderFactory; /** * @author Stian Thorgersen */ -public interface MongoConnectionProviderFactory extends ProviderFactory { +public interface MongoConnectionProviderFactory extends MonitorableProviderFactory { } diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index 5590f9576e1..f4e4c6dcf26 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -1,21 +1,47 @@
-

Server Info

+

Server Info

- +
+ + + + + + + + + + + + +
Keycloak Version{{serverInfo.version}}
Server Time{{serverInfo.serverTime}} (update)
Server Uptime{{serverInfo.serverUptime}}
+ +
+ Java VM Memory Statistics +
+ + + + + + + + + + + + + +
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
+
+
+ +
+ System Info +
+ - - - - - - - - - - - - - + @@ -66,23 +92,59 @@ -
Version{{serverInfo.version}}
Server Time{{serverInfo.serverTime}} (update)
Server Uptime{{serverInfo.serverUptime}}
Current Working DirectoryCurrent Working Directory {{serverInfo.systemInfo.userDir}}
OS Architecture {{serverInfo.systemInfo.osArchitecture}}
- -

Java VM Memory Statistics

- - - - - - - - - - - - - -
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
+ +
+
+ + +
+ Database Info +
+ + + + + + + + + + + + + + + + + +
Database URL{{serverInfo.jpaInfo.jdbcUrl}}
Database User{{serverInfo.jpaInfo.databaseUser}}
Database Type{{serverInfo.jpaInfo.databaseProduct}}
Database Driver{{serverInfo.jpaInfo.databaseDriver}}
+
+
+ +
+ Mongo DB Info +
+ + + + + + + + + + + + + + + + + +
Address{{serverInfo.mongoDbInfo.address}}
Database{{serverInfo.mongoDbInfo.database}}
User{{serverInfo.mongoDbInfo.user}}
Driver Version{{serverInfo.mongoDbInfo.driverVersion}}
+
+
+
Providers @@ -93,7 +155,7 @@ - + @@ -117,7 +179,7 @@
SPISPI Providers
- + diff --git a/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java new file mode 100644 index 00000000000..7b9c95c9218 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java @@ -0,0 +1,18 @@ +package org.keycloak.provider; + +/** + * Provider factory for provider which is monitorable. It means some info about it can be shown on "Server Info" page or accessed over Operational monitoring endpoint. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public interface MonitorableProviderFactory extends ProviderFactory { + + /** + * Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc). + * Is used to be shown on "Server Info" page or in Operational monitoring endpoint. + * + * @return extendion of {@link ProviderOperationalInfo} + */ + public ProviderOperationalInfo getOperationalInfo(); + +} diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java new file mode 100644 index 00000000000..ca3e8a6849a --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java @@ -0,0 +1,22 @@ +package org.keycloak.provider; + +import java.io.Serializable; + +/** + * Operational info about given Provider. + * Contains info about Provider that can be shown on "Server Info" page or accessed over Operational monitoring endpoint. + * + * @author Vlastimil Elias (velias at redhat dot com) + * @see MonitorableProviderFactory + */ +public interface ProviderOperationalInfo extends Serializable { + + /** + * Return true if provider is OK from operation point of view. It means it is able to perform necessary work. + * It can return false for example if remote DB of JPA provider is not available, or LDAP server of LDAP based user federation provider is not available. + * + * @return true if provider is OK to perform his operation. + */ + boolean isOk(); + +} diff --git a/services/pom.xml b/services/pom.xml index da71e9ae6f6..16fef06d5cb 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -39,6 +39,21 @@ keycloak-connections-http-client provided + + org.keycloak + keycloak-connections-jpa + provided + + + org.hibernate + hibernate-entitymanager + provided + + + org.keycloak + keycloak-connections-mongo + provided + org.keycloak keycloak-forms-common-freemarker 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 c600b92e4b4..91610db0c43 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,5 +1,6 @@ package org.keycloak.services.resources.admin; +import java.io.Serializable; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -13,9 +14,13 @@ 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; import org.keycloak.broker.provider.IdentityProviderFactory; +import org.keycloak.connections.jpa.JpaConnectionProvider; +import org.keycloak.connections.mongo.DefaultMongoConnectionFactoryProvider.MongoDbInfo; +import org.keycloak.connections.mongo.MongoConnectionProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; import org.keycloak.events.admin.OperationType; @@ -29,8 +34,10 @@ import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.ProtocolMapper; +import org.keycloak.provider.MonitorableProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.ProviderOperationalInfo; import org.keycloak.provider.Spi; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -41,6 +48,8 @@ import org.keycloak.social.SocialIdentityProvider; * @author Stian Thorgersen */ public class ServerInfoAdminResource { + + private static final Logger logger = Logger.getLogger(ServerInfoAdminResource.class); private static final Map> ENUMS = createEnumsMap(EventType.class, OperationType.class); @@ -58,6 +67,8 @@ public class ServerInfoAdminResource { info.version = Version.VERSION; info.serverTime = new Date().toString(); info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); + info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); + info.systemInfo = (new SystemInfo()).init(); setSocialProviders(info); setIdentityProviders(info); setThemes(info); @@ -68,6 +79,21 @@ public class ServerInfoAdminResource { setProtocolMapperTypes(info); setBuiltinProtocolMappers(info); info.setEnums(ENUMS); + + ProviderFactory jpf = session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class); + if(jpf!=null && jpf instanceof MonitorableProviderFactory){ + info.jpaInfo = ((MonitorableProviderFactory)jpf).getOperationalInfo(); + } else { + logger.debug("JPA provider not found or is not monitorable"); + } + + ProviderFactory mpf = session.getKeycloakSessionFactory().getProviderFactory(MongoConnectionProvider.class); + if(mpf!=null && mpf instanceof MonitorableProviderFactory){ + info.mongoDbInfo = ((MonitorableProviderFactory)mpf).getOperationalInfo(); + } else { + logger.debug("Mongo provider not found or is not monitorable"); + } + return info; } @@ -191,10 +217,28 @@ public class ServerInfoAdminResource { } } - public static class MemoryInfo{ + public static class MemoryInfo implements Serializable { + + protected long total; + + protected long used; + + public MemoryInfo(){ + } + + /** + * Fill object fwith info. + * @param runtime used to get memory info from. + * @return itself for chaining + */ + public MemoryInfo init(Runtime runtime){ + total = runtime.maxMemory(); + used = runtime.totalMemory() - runtime.freeMemory(); + return this; + } public long getTotal(){ - return Runtime.getRuntime().maxMemory(); + return total; } public String getTotalFormated(){ @@ -210,7 +254,7 @@ public class ServerInfoAdminResource { } public long getUsed(){ - return Runtime.getRuntime().totalMemory(); + return used; } public String getUsedFormated(){ @@ -218,7 +262,7 @@ public class ServerInfoAdminResource { } public long getFreePercentage(){ - return getFree()*100/getTotal(); + return getFree() * 100 / getTotal(); } private String formatMemory(long bytes){ @@ -233,71 +277,109 @@ public class ServerInfoAdminResource { } - public static class SystemInfo { + public static class SystemInfo implements Serializable { + + protected String javaVersion; + protected String javaVendor; + protected String javaVm; + protected String javaVmVersion; + protected String javaRuntime; + protected String javaHome; + protected String osName; + protected String osArchitecture; + protected String osVersion; + protected String fileEncoding; + protected String userName; + protected String userDir; + protected String userTimezone; + protected String userLocale; + + public SystemInfo() { + } + + /** + * Fill object with info about current system loaded from {@link System} properties. + * @return object itself for chaining + */ + protected SystemInfo init(){ + javaVersion = System.getProperty("java.version"); + javaVendor = System.getProperty("java.vendor"); + javaVm = System.getProperty("java.vm.name"); + javaVmVersion = System.getProperty("java.vm.version"); + javaRuntime = System.getProperty("java.runtime.name"); + javaHome = System.getProperty("java.home"); + osName = System.getProperty("os.name"); + osArchitecture = System.getProperty("os.arch"); + osVersion = System.getProperty("os.version"); + fileEncoding = System.getProperty("file.encoding"); + userName = System.getProperty("user.name"); + userDir = System.getProperty("user.dir"); + userTimezone = System.getProperty("user.timezone"); + userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + return this; + } + public String getJavaVersion(){ - return System.getProperty("java.version"); + return javaVersion; } public String getJavaVendor(){ - return System.getProperty("java.vendor"); + return javaVendor; } public String getJavaVm(){ - return System.getProperty("java.vm.name"); + return javaVm; } public String getJavaVmVersion(){ - return System.getProperty("java.vm.version"); + return javaVmVersion; } public String getJavaRuntime(){ - return System.getProperty("java.runtime.name"); + return javaRuntime; } public String getJavaHome(){ - return System.getProperty("java.home"); + return javaHome; } public String getOsName(){ - return System.getProperty("os.name"); + return osName; } public String getOsArchitecture(){ - return System.getProperty("os.arch"); + return osArchitecture; } public String getOsVersion(){ - return System.getProperty("os.version"); + return osVersion; } public String getFileEncoding(){ - return System.getProperty("file.encoding"); + return fileEncoding; } public String getUserName(){ - return System.getProperty("user.name"); + return userName; } public String getUserDir(){ - return System.getProperty("user.dir"); + return userDir; } public String getUserTimezone(){ - return System.getProperty("user.timezone"); + return userTimezone; } public String getUserLocale(){ - return (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + return userLocale; } - } - public static class ServerInfoRepresentation { + public static class ServerInfoRepresentation implements Serializable { private String version; - private String serverTime; - private long serverStartupTime; private Map> themes; @@ -314,26 +396,44 @@ public class ServerInfoAdminResource { private Map> builtinProtocolMappers; private Map> enums; + + private MemoryInfo memoryInfo; + private SystemInfo systemInfo; + + private ProviderOperationalInfo jpaInfo; + private ProviderOperationalInfo mongoDbInfo; public ServerInfoRepresentation() { } public SystemInfo getSystemInfo(){ - return new SystemInfo(); + return systemInfo; } public MemoryInfo getMemoryInfo(){ - return new MemoryInfo(); + return memoryInfo; + } + + public ProviderOperationalInfo getJpaInfo() { + return jpaInfo; + } + + public ProviderOperationalInfo getMongoDbInfo() { + return mongoDbInfo; } public String getServerTime() { return serverTime; } + public long getServerStartupTime() { + return serverStartupTime; + } + /** * @return server startup time formatted */ - public String getServerStartupTime() { + public String getServerStartupTimeFormatted() { return (new Date(serverStartupTime)).toString(); } @@ -420,7 +520,7 @@ public class ServerInfoAdminResource { } } - public static class SpiInfoRepresentation { + public static class SpiInfoRepresentation implements Serializable { private String name; private boolean internal; private Set implementations; 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 3bde1cb7406..85a81bbbebd 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,10 +21,27 @@ */ 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; import org.keycloak.Config; +import org.keycloak.Version; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.Constants; @@ -40,22 +57,8 @@ 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.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.Set; +import org.keycloak.testsuite.rule.AbstractKeycloakRule; /** * Tests Undertow Adapter @@ -295,4 +298,34 @@ public class AdminAPITest { testCreateRealm("/admin-test/testrealm.json"); } + @Test + public void testServerInfo() { + + String token = createToken(); + final String authHeader = "Bearer " + token; + ClientRequestFilter authFilter = new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); + } + }; + Client client = ClientBuilder.newBuilder().register(authFilter).build(); + UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); + WebTarget target = client.target(AdminRoot.adminBaseUrl(authBase).path("serverinfo")); + + Map response = target.request().accept("application/json").get(Map.class); + + Assert.assertNotNull(response); + Assert.assertEquals(Version.VERSION, response.get("version")); + Assert.assertNotNull(response.get("serverTime")); + Assert.assertNotNull(response.get("serverStartupTime")); + + Assert.assertNotNull(response.get("memoryInfo")); + Assert.assertNotNull(response.get("jpaInfo")); + Assert.assertNull(response.get("mongoDbInfo")); + + System.out.println(response); + + } + } From 85816be96716b46fd6d622601764af8a9b7f7339 Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Wed, 22 Jul 2015 13:35:56 +0200 Subject: [PATCH 03/14] KEYCLOAK-1542 - code cleanup ahead of PR --- .../jpa/DefaultJpaConnectionProviderFactory.java | 6 ------ .../mongo/DefaultMongoConnectionFactoryProvider.java | 6 ------ .../org/keycloak/provider/ProviderOperationalInfo.java | 8 -------- .../services/resources/admin/ServerInfoAdminResource.java | 1 - 4 files changed, 21 deletions(-) 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 36f3c09cce7..1795cd13c5f 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 @@ -231,12 +231,6 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide public String getDatabaseProduct() { return databaseProduct; } - - @Override - public boolean isOk() { - // TODO KEYCLOAK-1578 - implement operational monitoring of JPA DB connection - return true; - } } } 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 c8d1cbaed4a..248b880be6c 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 @@ -212,12 +212,6 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro public String driverVersion; public String user; - @Override - public boolean isOk() { - // TODO KEYCLOAK-1578 - implement operational monitoring of Mongo DB connection - return true; - } - public String getAddress() { return address; } diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java index ca3e8a6849a..e37544d2768 100644 --- a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java +++ b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java @@ -11,12 +11,4 @@ import java.io.Serializable; */ public interface ProviderOperationalInfo extends Serializable { - /** - * Return true if provider is OK from operation point of view. It means it is able to perform necessary work. - * It can return false for example if remote DB of JPA provider is not available, or LDAP server of LDAP based user federation provider is not available. - * - * @return true if provider is OK to perform his operation. - */ - boolean isOk(); - } 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 91610db0c43..dbb0ff0c8f1 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 @@ -19,7 +19,6 @@ import org.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; import org.keycloak.connections.jpa.JpaConnectionProvider; -import org.keycloak.connections.mongo.DefaultMongoConnectionFactoryProvider.MongoDbInfo; import org.keycloak.connections.mongo.MongoConnectionProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; From 1c142cb17074bf91f73e3f7ded7fa307da1e8afb Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Wed, 22 Jul 2015 14:28:08 +0200 Subject: [PATCH 04/14] KEYCLOAK-1542 - code formatting cleanup --- .../DefaultJpaConnectionProviderFactory.java | 385 +++++++++--------- ...DefaultMongoConnectionFactoryProvider.java | 377 +++++++++-------- .../admin/ServerInfoAdminResource.java | 28 +- .../testsuite/admin/AdminAPITest.java | 33 +- 4 files changed, 420 insertions(+), 403 deletions(-) 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 1795cd13c5f..aac1cdebd47 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 Stian Thorgersen */ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory { - private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); + private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); - private volatile EntityManagerFactory emf; + private volatile EntityManagerFactory emf; - private Config.Scope config; + private Config.Scope config; + + private DatabaseInfo databaseInfo; - private DatabaseInfo databaseInfo; + @Override + public JpaConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @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); + } - 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 void close() { - if (emf != null) { - emf.close(); - } - } + @Override + public String getId() { + return "default"; + } - @Override - public String getId() { - return "default"; - } + @Override + public void init(Config.Scope config) { + this.config = config; + } - @Override - public void init(Config.Scope config) { - this.config = config; - } + @Override + public void postInit(KeycloakSessionFactory factory) { - @Override - public void postInit(KeycloakSessionFactory factory) { + } - } + private void lazyInit(KeycloakSession session) { + if (emf == null) { + synchronized (this) { + if (emf == null) { + logger.debug("Initializing JPA connections"); - private void lazyInit(KeycloakSession session) { - if (emf == null) { - synchronized (this) { - if (emf == null) { - logger.debug("Initializing JPA connections"); + Connection connection = null; - Connection connection = null; + String databaseSchema = config.get("databaseSchema"); - String databaseSchema = config.get("databaseSchema"); + Map properties = new HashMap(); - Map properties = new HashMap(); + String unitName = "keycloak-default"; - 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 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 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 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); + } - 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; + } + } - 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)); - 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"); - connection = getConnection(); - prepareDatabaseInfo(connection); + } 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()); + } + } - if (databaseSchema != null) { - logger.trace("Updating database"); + 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; + } - JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class); - if (updater == null) { - throw new RuntimeException("Can't update database: JPA updater provider not found"); - } + public static class DatabaseInfo implements ProviderOperationalInfo { + protected String jdbcUrl; + protected String databaseUser; + protected String databaseProduct; + protected String databaseDriver; - 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) { - } + public String getJdbcUrl() { + return jdbcUrl; + } - 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); - } + public String getDatabaseDriver() { + return databaseDriver; + } - logger.trace("Database update completed"); - } + public String getDatabaseUser() { + return databaseUser; + } - 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; - } - } + 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 248b880be6c..2df4b853630 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 Stian Thorgersen */ 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", }; + // 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 static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class); - private volatile MongoClient client; + private volatile MongoClient client; - private MongoStore mongoStore; - private DB db; - protected Config.Scope config; + private MongoStore mongoStore; + private DB db; + protected Config.Scope config; + + private MongoDbInfo mongoDbInfo; - private MongoDbInfo mongoDbInfo; + @Override + public MongoConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @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); + } - 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 init(Config.Scope config) { - this.config = config; - } + @Override + public void postInit(KeycloakSessionFactory factory) { - @Override - public void postInit(KeycloakSessionFactory factory) { + } - } - private void lazyInit(KeycloakSession session) { - if (client == null) { - synchronized (this) { - if (client == null) { - try { - this.client = createMongoClient(); + 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 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); + 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"); - } + 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); - } - } + 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); - } - } - } - } - } + 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; - } + 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 void close() { + if (client != null) { + client.close(); + } + } - @Override - public String getId() { - return "default"; - } + @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"); + /** + * 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"); + String user = config.get("user"); + String password = config.get("password"); - MongoClientOptions clientOptions = getClientOptions(); + 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); - } + 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; + } - mongoDbInfo = new MongoDbInfo(); - mongoDbInfo.driverVersion = client.getVersion(); - mongoDbInfo.address = client.getAddress().toString(); - mongoDbInfo.database = dbName; - mongoDbInfo.user = user; + 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()); + } - logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); - return client; - } + return builder.build(); + } - 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()); - } + 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); + } + } + } - return builder.build(); - } + 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; + } - 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); - } - } - } + public static class MongoDbInfo implements ProviderOperationalInfo { - 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); - } - } - } + public String address; + public String database; + public String driverVersion; + public String user; - @Override - public ProviderOperationalInfo getOperationalInfo() { - return mongoDbInfo; - } + public String getAddress() { + return address; + } - public static class MongoDbInfo implements ProviderOperationalInfo { + public String getDatabase() { + return database; + } - 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; - } - } + 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 dbb0ff0c8f1..3b69304b065 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 Stian Thorgersen */ @@ -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 85a81bbbebd..2cca19a0c98 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 From 99f74acb94f1761417be3000d8615287866e2807 Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Thu, 23 Jul 2015 16:39:27 +0200 Subject: [PATCH 05/14] KEYCLOAK-1542 - rewrote showing info from providers to be generic --- .../DefaultJpaConnectionProviderFactory.java | 48 +-- .../jpa/JpaConnectionProviderFactory.java | 4 +- ...DefaultMongoConnectionFactoryProvider.java | 43 +- .../mongo/MongoConnectionProviderFactory.java | 4 +- .../theme/base/admin/resources/js/app.js | 8 +- .../admin/resources/js/controllers/realm.js | 7 + .../theme/base/admin/resources/js/loaders.js | 4 + .../theme/base/admin/resources/js/services.js | 3 + .../admin/resources/partials/server-info.html | 118 +++--- .../provider/MonitorableProviderFactory.java | 18 - .../provider/ProviderOperationalInfo.java | 14 - .../ServerInfoAwareProviderFactory.java | 20 + services/pom.xml | 15 - .../services/resources/admin/AdminRoot.java | 26 ++ .../admin/ServerInfoAdminResource.java | 254 +----------- .../admin/ServerInfoPageAdminResource.java | 375 ++++++++++++++++++ .../testsuite/admin/AdminAPITest.java | 34 +- 17 files changed, 555 insertions(+), 440 deletions(-) delete mode 100644 model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java delete mode 100644 model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java create mode 100644 model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java 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 aac1cdebd47..a79c82b2286 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 @@ -6,20 +6,19 @@ import org.keycloak.Config; import org.keycloak.connections.jpa.updater.JpaUpdaterProvider; 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.LinkedHashMap; import java.util.Map; /** @@ -33,7 +32,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide private Config.Scope config; - private DatabaseInfo databaseInfo; + private Map operationalInfo; @Override public JpaConnectionProvider create(KeycloakSession session) { @@ -127,7 +126,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide connection = getConnection(); try{ - prepareDatabaseInfo(connection); + prepareOperationalInfo(connection); if (databaseSchema != null) { logger.trace("Updating database"); @@ -180,16 +179,16 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide } } - protected void prepareDatabaseInfo(Connection connection) { + protected void prepareOperationalInfo(Connection connection) { try { - databaseInfo = new DatabaseInfo(); + operationalInfo = new LinkedHashMap<>(); DatabaseMetaData md = connection.getMetaData(); - databaseInfo.databaseDriver = md.getDriverName() + " " + md.getDriverVersion(); - databaseInfo.databaseProduct = md.getDatabaseProductName() + " " + md.getDatabaseProductVersion(); - databaseInfo.databaseUser = md.getUserName(); - databaseInfo.jdbcUrl = md.getURL(); + operationalInfo.put("databaseUrl",md.getURL()); + operationalInfo.put("databaseUser", md.getUserName()); + operationalInfo.put("databaseProduct", md.getDatabaseProductName() + " " + md.getDatabaseProductVersion()); + operationalInfo.put("databaseDriver", md.getDriverName() + " " + md.getDriverVersion()); } catch (SQLException e) { - logger.warn("Unable to get database info due " + e.getMessage()); + logger.warn("Unable to prepare operational info due database exception: " + e.getMessage()); } } @@ -209,31 +208,8 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide } @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; - } + public Map getOperationalInfo() { + return operationalInfo; } } diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java index ab2b119c29c..288e403335a 100644 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java @@ -1,10 +1,10 @@ package org.keycloak.connections.jpa; -import org.keycloak.provider.MonitorableProviderFactory; +import org.keycloak.provider.ServerInfoAwareProviderFactory; /** * @author Stian Thorgersen */ -public interface JpaConnectionProviderFactory extends MonitorableProviderFactory { +public interface JpaConnectionProviderFactory extends ServerInfoAwareProviderFactory { } 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 2df4b853630..8da15b69c12 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 @@ -14,13 +14,13 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati import org.keycloak.connections.mongo.updater.MongoUpdaterProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.provider.ProviderOperationalInfo; import javax.net.ssl.SSLSocketFactory; - import java.lang.reflect.Method; import java.net.UnknownHostException; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; /** * @author Stian Thorgersen @@ -61,7 +61,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro private DB db; protected Config.Scope config; - private MongoDbInfo mongoDbInfo; + private Map operationalInfo; @Override public MongoConnectionProvider create(KeycloakSession session) { @@ -165,11 +165,11 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro 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; + operationalInfo = new LinkedHashMap<>(); + operationalInfo.put("mongoServerAddress", client.getAddress().toString()); + operationalInfo.put("mongoDatabaseName", dbName); + operationalInfo.put("mongoUser", user); + operationalInfo.put("mongoDriverVersion", client.getVersion()); logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); return client; @@ -219,31 +219,8 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro } @Override - public ProviderOperationalInfo getOperationalInfo() { - return mongoDbInfo; + public Map getOperationalInfo() { + return operationalInfo; } - 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/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java index 3b3a00e5602..bce5fe4b9cf 100644 --- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java +++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java @@ -1,9 +1,9 @@ package org.keycloak.connections.mongo; -import org.keycloak.provider.MonitorableProviderFactory; +import org.keycloak.provider.ServerInfoAwareProviderFactory; /** * @author Stian Thorgersen */ -public interface MongoConnectionProviderFactory extends MonitorableProviderFactory { +public interface MongoConnectionProviderFactory extends ServerInfoAwareProviderFactory { } diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js index 3f8618bf76d..8797f5ef4b3 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js @@ -1112,7 +1112,13 @@ module.config([ '$routeProvider', function($routeProvider) { controller : 'AuthenticationConfigCreateCtrl' }) .when('/server-info', { - templateUrl : resourceUrl + '/partials/server-info.html' + templateUrl : resourceUrl + '/partials/server-info.html', + resolve : { + serverInfoPage : function(ServerInfoPageLoader) { + return ServerInfoPageLoader(); + } + }, + controller : 'ServerInfoPageCtrl' }) .when('/logout', { templateUrl : resourceUrl + '/partials/home.html', diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js index 59a3f8518b9..243fff73a7c 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js @@ -113,6 +113,13 @@ module.controller('HomeCtrl', function(Realm, Auth, $location) { }); }); +module.controller('ServerInfoPageCtrl', function($scope, ServerInfoPage) { + $scope.serverInfoPage = ServerInfoPage.get(); + $scope.serverInfoPageUpdate = function() { + $scope.serverInfoPage = ServerInfoPage.get(); + }; +}); + module.controller('RealmListCtrl', function($scope, Realm, Current) { $scope.realms = Realm.query(); Current.realms = $scope.realms; diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js index 773f6f02718..329802bc3cf 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js @@ -39,6 +39,10 @@ module.factory('ServerInfoLoader', function(Loader, ServerInfo, $q) { return Loader.get(ServerInfo); }); +module.factory('ServerInfoPageLoader', function(Loader, ServerInfoPage, $q) { + return Loader.get(ServerInfoPage); +}); + module.factory('RealmLoader', function(Loader, Realm, $route, $q) { return Loader.get(Realm, function() { return { diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js index 5e9fefda636..7bb14804f89 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js @@ -205,6 +205,9 @@ module.factory('ServerInfo', function($resource) { return $resource(authUrl + '/admin/serverinfo'); }); +module.factory('ServerInfoPage', function($resource) { + return $resource(authUrl + '/admin/serverinfopage'); +}); module.factory('ClientProtocolMapper', function($resource) { diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index f4e4c6dcf26..0dfac4cb9ac 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -4,15 +4,15 @@
SPISPI Providers
- + - + - +
Keycloak Version{{serverInfo.version}}{{serverInfoPage.version}}
Server Time{{serverInfo.serverTime}} (update){{serverInfoPage.serverTime}} (update)
Server Uptime{{serverInfo.serverUptime}}{{serverInfoPage.serverUptime}}
@@ -22,15 +22,15 @@ - + - + - +
Total Memory{{serverInfo.memoryInfo.totalFormated}}{{serverInfoPage.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%){{serverInfoPage.memoryInfo.freeFormated}} ({{serverInfoPage.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}{{serverInfoPage.memoryInfo.usedFormated}}
@@ -42,109 +42,73 @@ - + - + - + - + - + - + - + - + - + - + - + - + - +
Current Working Directory{{serverInfo.systemInfo.userDir}}{{serverInfoPage.systemInfo.userDir}}
Java Version{{serverInfo.systemInfo.javaVersion}}{{serverInfoPage.systemInfo.javaVersion}}
Java Vendor{{serverInfo.systemInfo.javaVendor}}{{serverInfoPage.systemInfo.javaVendor}}
Java Runtime{{serverInfo.systemInfo.javaRuntime}}{{serverInfoPage.systemInfo.javaRuntime}}
Java VM{{serverInfo.systemInfo.javaVm}}{{serverInfoPage.systemInfo.javaVm}}
Java VM Version{{serverInfo.systemInfo.javaVmVersion}}{{serverInfoPage.systemInfo.javaVmVersion}}
Java Home{{serverInfo.systemInfo.javaHome}}{{serverInfoPage.systemInfo.javaHome}}
User Name{{serverInfo.systemInfo.userName}}{{serverInfoPage.systemInfo.userName}}
User Timezone{{serverInfo.systemInfo.userTimezone}}{{serverInfoPage.systemInfo.userTimezone}}
User Locale{{serverInfo.systemInfo.userLocale}}{{serverInfoPage.systemInfo.userLocale}}
System Encoding{{serverInfo.systemInfo.fileEncoding}}{{serverInfoPage.systemInfo.fileEncoding}}
Operating System{{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}}{{serverInfoPage.systemInfo.osName}} {{serverInfoPage.systemInfo.osVersion}}
OS Architecture{{serverInfo.systemInfo.osArchitecture}}{{serverInfoPage.systemInfo.osArchitecture}}
-
+
Database Info
- - - - - - - - - - - - - - - + + +
Database URL{{serverInfo.jpaInfo.jdbcUrl}}
Database User{{serverInfo.jpaInfo.databaseUser}}
Database Type{{serverInfo.jpaInfo.databaseProduct}}
Database Driver{{serverInfo.jpaInfo.databaseDriver}}
{{key}}{{value}}
-
- Mongo DB Info -
- - - - - - - - - - - - - - - - - -
Address{{serverInfo.mongoDbInfo.address}}
Database{{serverInfo.mongoDbInfo.database}}
User{{serverInfo.mongoDbInfo.user}}
Driver Version{{serverInfo.mongoDbInfo.driverVersion}}
-
-
-
Providers @@ -160,11 +124,23 @@ - + {{spi.name}} -
- {{provider}} +
+ {{provider.name}} + + + + + + + +
{{key}}{{value}}
+
@@ -184,11 +160,23 @@ - + {{spi.name}} -
- {{provider}} +
+ {{provider.name}} + + + + + + + +
{{key}}{{value}}
+
diff --git a/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java deleted file mode 100644 index 7b9c95c9218..00000000000 --- a/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.keycloak.provider; - -/** - * Provider factory for provider which is monitorable. It means some info about it can be shown on "Server Info" page or accessed over Operational monitoring endpoint. - * - * @author Vlastimil Elias (velias at redhat dot com) - */ -public interface MonitorableProviderFactory extends ProviderFactory { - - /** - * Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc). - * Is used to be shown on "Server Info" page or in Operational monitoring endpoint. - * - * @return extendion of {@link ProviderOperationalInfo} - */ - public ProviderOperationalInfo getOperationalInfo(); - -} diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java deleted file mode 100644 index e37544d2768..00000000000 --- a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.keycloak.provider; - -import java.io.Serializable; - -/** - * Operational info about given Provider. - * Contains info about Provider that can be shown on "Server Info" page or accessed over Operational monitoring endpoint. - * - * @author Vlastimil Elias (velias at redhat dot com) - * @see MonitorableProviderFactory - */ -public interface ProviderOperationalInfo extends Serializable { - -} diff --git a/model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java new file mode 100644 index 00000000000..97d17b1dcc0 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java @@ -0,0 +1,20 @@ +package org.keycloak.provider; + +import java.util.Map; + +/** + * Marker interface for ProviderFactory of Provider which wants to show some info on "Server Info" page in Admin console. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public interface ServerInfoAwareProviderFactory extends ProviderFactory { + + /** + * Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc) which is + * shown on "Server Info" page. + * + * @return Map with keys describing value and relevant values itself + */ + public Map getOperationalInfo(); + +} diff --git a/services/pom.xml b/services/pom.xml index 16fef06d5cb..da71e9ae6f6 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -39,21 +39,6 @@ keycloak-connections-http-client provided - - org.keycloak - keycloak-connections-jpa - provided - - - org.hibernate - hibernate-entitymanager - provided - - - org.keycloak - keycloak-connections-mongo - provided - org.keycloak keycloak-forms-common-freemarker diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java index e1d1fa3c48a..6b3ca3eafa7 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java @@ -218,6 +218,32 @@ public class AdminRoot { return adminResource; } + /** + * Operational information about the server for "Server Info" page + * + * @param headers + * @return + */ + @Path("serverinfopage") + public ServerInfoPageAdminResource getServerInfoPage(@Context final HttpHeaders headers) { + handlePreflightRequest(); + + AdminAuth auth = authenticateRealmAdminRequest(headers); + if (!isAdmin(auth)) { + throw new ForbiddenException(); + } + + if (auth != null) { + logger.debug("authenticated admin access for: " + auth.getUser().getUsername()); + } + + Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response); + + ServerInfoPageAdminResource adminResource = new ServerInfoPageAdminResource(); + ResteasyProviderFactory.getInstance().injectProperties(adminResource); + return adminResource; + } + protected boolean isAdmin(AdminAuth auth) { RealmManager realmManager = new RealmManager(session); 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 3b69304b065..4f1c22575b0 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,11 +1,8 @@ package org.keycloak.services.resources.admin; -import org.jboss.logging.Logger; import org.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; -import org.keycloak.connections.jpa.JpaConnectionProvider; -import org.keycloak.connections.mongo.MongoConnectionProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; import org.keycloak.events.admin.OperationType; @@ -19,10 +16,8 @@ import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.ProtocolMapper; -import org.keycloak.provider.MonitorableProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; -import org.keycloak.provider.ProviderOperationalInfo; import org.keycloak.provider.Spi; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -31,13 +26,11 @@ 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; @@ -46,8 +39,6 @@ import java.util.Set; * @author Stian Thorgersen */ public class ServerInfoAdminResource { - - private static final Logger logger = Logger.getLogger(ServerInfoAdminResource.class); private static final Map> ENUMS = createEnumsMap(EventType.class, OperationType.class); @@ -64,9 +55,6 @@ public class ServerInfoAdminResource { ServerInfoRepresentation info = new ServerInfoRepresentation(); info.version = Version.VERSION; info.serverTime = new Date().toString(); - info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); - info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); - info.systemInfo = (new SystemInfo()).init(); setSocialProviders(info); setIdentityProviders(info); setThemes(info); @@ -77,21 +65,6 @@ public class ServerInfoAdminResource { setProtocolMapperTypes(info); setBuiltinProtocolMappers(info); info.setEnums(ENUMS); - - ProviderFactory jpf = session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class); - if(jpf!=null && jpf instanceof MonitorableProviderFactory){ - info.jpaInfo = ((MonitorableProviderFactory)jpf).getOperationalInfo(); - } else { - logger.debug("JPA provider not found or is not monitorable"); - } - - ProviderFactory mpf = session.getKeycloakSessionFactory().getProviderFactory(MongoConnectionProvider.class); - if(mpf!=null && mpf instanceof MonitorableProviderFactory){ - info.mongoDbInfo = ((MonitorableProviderFactory)mpf).getOperationalInfo(); - } else { - logger.debug("Mongo provider not found or is not monitorable"); - } - return info; } @@ -214,170 +187,12 @@ public class ServerInfoAdminResource { info.clientImporters.add(data); } } - - public static class MemoryInfo implements Serializable { - - protected long total; - protected long used; - - public MemoryInfo(){ - } - - /** - * Fill object fwith info. - * @param runtime used to get memory info from. - * @return itself for chaining - */ - public MemoryInfo init(Runtime runtime){ - total = runtime.maxMemory(); - used = runtime.totalMemory() - runtime.freeMemory(); - return this; - } - - public long getTotal(){ - return total; - } - - public String getTotalFormated(){ - return formatMemory(getTotal()); - } - - public long getFree(){ - return getTotal() - getUsed(); - } - public String getFreeFormated(){ - return formatMemory(getFree()); - } - - public long getUsed(){ - return used; - } - - public String getUsedFormated(){ - return formatMemory(getUsed()); - } - - public long getFreePercentage(){ - return getFree() * 100 / getTotal(); - } - - private String formatMemory(long bytes){ - if(bytes > 1024L*1024L){ - return bytes/(1024L *1024L) + " MB"; - } else if(bytes > 1024L){ - return bytes/(1024L) + " kB"; - } else { - return bytes + " B"; - } - } - - } - - public static class SystemInfo implements Serializable { - - protected String javaVersion; - protected String javaVendor; - protected String javaVm; - protected String javaVmVersion; - protected String javaRuntime; - protected String javaHome; - protected String osName; - protected String osArchitecture; - protected String osVersion; - protected String fileEncoding; - protected String userName; - protected String userDir; - protected String userTimezone; - protected String userLocale; - - public SystemInfo() { - } - - /** - * Fill object with info about current system loaded from {@link System} properties. - * @return object itself for chaining - */ - protected SystemInfo init(){ - javaVersion = System.getProperty("java.version"); - javaVendor = System.getProperty("java.vendor"); - javaVm = System.getProperty("java.vm.name"); - javaVmVersion = System.getProperty("java.vm.version"); - javaRuntime = System.getProperty("java.runtime.name"); - javaHome = System.getProperty("java.home"); - osName = System.getProperty("os.name"); - osArchitecture = System.getProperty("os.arch"); - osVersion = System.getProperty("os.version"); - fileEncoding = System.getProperty("file.encoding"); - userName = System.getProperty("user.name"); - userDir = System.getProperty("user.dir"); - userTimezone = System.getProperty("user.timezone"); - userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); - return this; - } - - public String getJavaVersion(){ - return javaVersion; - } - - public String getJavaVendor(){ - return javaVendor; - } - - public String getJavaVm(){ - return javaVm; - } - - public String getJavaVmVersion(){ - return javaVmVersion; - } - - public String getJavaRuntime(){ - return javaRuntime; - } - - public String getJavaHome(){ - return javaHome; - } - - public String getOsName(){ - return osName; - } - - public String getOsArchitecture(){ - return osArchitecture; - } - - public String getOsVersion(){ - return osVersion; - } - - public String getFileEncoding(){ - return fileEncoding; - } - - public String getUserName(){ - return userName; - } - - public String getUserDir(){ - return userDir; - } - - public String getUserTimezone(){ - return userTimezone; - } - - public String getUserLocale(){ - return userLocale; - } - } - - public static class ServerInfoRepresentation implements Serializable { + public static class ServerInfoRepresentation { private String version; + private String serverTime; - private long serverStartupTime; private Map> themes; @@ -393,76 +208,13 @@ public class ServerInfoAdminResource { private Map> builtinProtocolMappers; private Map> enums; - - private MemoryInfo memoryInfo; - private SystemInfo systemInfo; - - private ProviderOperationalInfo jpaInfo; - private ProviderOperationalInfo mongoDbInfo; public ServerInfoRepresentation() { } - - public SystemInfo getSystemInfo(){ - return systemInfo; - } - - public MemoryInfo getMemoryInfo(){ - return memoryInfo; - } - - public ProviderOperationalInfo getJpaInfo() { - return jpaInfo; - } - - public ProviderOperationalInfo getMongoDbInfo() { - return mongoDbInfo; - } public String getServerTime() { return serverTime; } - - public long getServerStartupTime() { - return serverStartupTime; - } - - /** - * @return server startup time formatted - */ - public String getServerStartupTimeFormatted() { - return (new Date(serverStartupTime)).toString(); - } - - /** - * @return server uptime in millis - */ - public long getServerUptimeMillis(){ - return System.currentTimeMillis() - serverStartupTime; - } - - /** - * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" - */ - public String getServerUptime(){ - long diffInSeconds = getServerUptimeMillis()/1000; - long diff[] = new long[] { 0, 0, 0, 0 }; - /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); - /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; - /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; - /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); - - return String.format( - "%d day%s, %d hour%s, %d minute%s, %d second%s", - diff[0], - diff[0] != 1 ? "s" : "", - diff[1], - diff[1] != 1 ? "s" : "", - diff[2], - diff[2] != 1 ? "s" : "", - diff[3], - diff[3] != 1 ? "s" : ""); - } public String getVersion() { return version; @@ -517,7 +269,7 @@ public class ServerInfoAdminResource { } } - public static class SpiInfoRepresentation implements Serializable { + public static class SpiInfoRepresentation { private String name; private boolean internal; private Set implementations; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java new file mode 100644 index 00000000000..c6a720816cf --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java @@ -0,0 +1,375 @@ +package org.keycloak.services.resources.admin; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashSet; +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.models.KeycloakSession; +import org.keycloak.provider.ServerInfoAwareProviderFactory; +import org.keycloak.provider.Spi; + +/** + * REST endpoint which return info for "Server Info" page. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public class ServerInfoPageAdminResource { + + private static final Logger logger = Logger.getLogger(ServerInfoPageAdminResource.class); + + @Context + private KeycloakSession session; + + /** + * Returns a list of providers and other operational info about the page. + * + * @return + */ + @GET + public ServerInfoRepresentation getInfo() { + ServerInfoRepresentation info = new ServerInfoRepresentation(); + info.version = Version.VERSION; + info.serverTime = new Date().toString(); + info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); + info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); + info.systemInfo = (new SystemInfo()).init(); + setProviders(info); + return info; + } + + private void setProviders(ServerInfoRepresentation info) { + List providers = new LinkedList<>(); + for (Spi spi : ServiceLoader.load(Spi.class)) { + SpiInfoRepresentation spiRep = new SpiInfoRepresentation(); + spiRep.setName(spi.getName()); + spiRep.setInternal(spi.isInternal()); + spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass())); + Set s = session.listProviderIds(spi.getProviderClass()); + Set srs = new HashSet<>(); + + if(s!=null){ + for(String name: s){ + SpiImplementationRepresentation sr = new SpiImplementationRepresentation(name); + if(spiRep.isSystemInfo()){ + sr.setOperationalInfo(((ServerInfoAwareProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name)).getOperationalInfo()); + } + srs.add(sr); + } + } + spiRep.setImplementations(srs); + providers.add(spiRep); + } + info.providers = providers; + } + + + public static class MemoryInfo implements Serializable { + + protected long total; + protected long used; + + public MemoryInfo(){ + } + + /** + * Fill object fwith info. + * @param runtime used to get memory info from. + * @return itself for chaining + */ + public MemoryInfo init(Runtime runtime){ + total = runtime.maxMemory(); + used = runtime.totalMemory() - runtime.freeMemory(); + return this; + } + + public long getTotal(){ + return total; + } + + public String getTotalFormated(){ + return formatMemory(getTotal()); + } + + public long getFree(){ + return getTotal() - getUsed(); + } + + public String getFreeFormated(){ + return formatMemory(getFree()); + } + + public long getUsed(){ + return used; + } + + public String getUsedFormated(){ + return formatMemory(getUsed()); + } + + public long getFreePercentage(){ + return getFree() * 100 / getTotal(); + } + + private String formatMemory(long bytes){ + if(bytes > 1024L*1024L){ + return bytes/(1024L *1024L) + " MB"; + } else if(bytes > 1024L){ + return bytes/(1024L) + " kB"; + } else { + return bytes + " B"; + } + } + + } + + public static class SystemInfo implements Serializable { + + protected String javaVersion; + protected String javaVendor; + protected String javaVm; + protected String javaVmVersion; + protected String javaRuntime; + protected String javaHome; + protected String osName; + protected String osArchitecture; + protected String osVersion; + protected String fileEncoding; + protected String userName; + protected String userDir; + protected String userTimezone; + protected String userLocale; + + public SystemInfo() { + } + + /** + * Fill object with info about current system loaded from {@link System} properties. + * @return object itself for chaining + */ + protected SystemInfo init(){ + javaVersion = System.getProperty("java.version"); + javaVendor = System.getProperty("java.vendor"); + javaVm = System.getProperty("java.vm.name"); + javaVmVersion = System.getProperty("java.vm.version"); + javaRuntime = System.getProperty("java.runtime.name"); + javaHome = System.getProperty("java.home"); + osName = System.getProperty("os.name"); + osArchitecture = System.getProperty("os.arch"); + osVersion = System.getProperty("os.version"); + fileEncoding = System.getProperty("file.encoding"); + userName = System.getProperty("user.name"); + userDir = System.getProperty("user.dir"); + userTimezone = System.getProperty("user.timezone"); + userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + return this; + } + + public String getJavaVersion(){ + return javaVersion; + } + + public String getJavaVendor(){ + return javaVendor; + } + + public String getJavaVm(){ + return javaVm; + } + + public String getJavaVmVersion(){ + return javaVmVersion; + } + + public String getJavaRuntime(){ + return javaRuntime; + } + + public String getJavaHome(){ + return javaHome; + } + + public String getOsName(){ + return osName; + } + + public String getOsArchitecture(){ + return osArchitecture; + } + + public String getOsVersion(){ + return osVersion; + } + + public String getFileEncoding(){ + return fileEncoding; + } + + public String getUserName(){ + return userName; + } + + public String getUserDir(){ + return userDir; + } + + public String getUserTimezone(){ + return userTimezone; + } + + public String getUserLocale(){ + return userLocale; + } + } + + public static class ServerInfoRepresentation implements Serializable { + + private String version; + private String serverTime; + private long serverStartupTime; + + + private List providers; + + private MemoryInfo memoryInfo; + private SystemInfo systemInfo; + + public ServerInfoRepresentation() { + } + + public SystemInfo getSystemInfo(){ + return systemInfo; + } + + public MemoryInfo getMemoryInfo(){ + return memoryInfo; + } + + public String getServerTime() { + return serverTime; + } + + public long getServerStartupTime() { + return serverStartupTime; + } + + /** + * @return server startup time formatted + */ + public String getServerStartupTimeFormatted() { + return (new Date(serverStartupTime)).toString(); + } + + /** + * @return server uptime in millis + */ + public long getServerUptimeMillis(){ + return System.currentTimeMillis() - serverStartupTime; + } + + /** + * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" + */ + public String getServerUptime(){ + long diffInSeconds = getServerUptimeMillis()/1000; + long diff[] = new long[] { 0, 0, 0, 0 }; + /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); + /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; + /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; + /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); + + return String.format( + "%d day%s, %d hour%s, %d minute%s, %d second%s", + diff[0], + diff[0] != 1 ? "s" : "", + diff[1], + diff[1] != 1 ? "s" : "", + diff[2], + diff[2] != 1 ? "s" : "", + diff[3], + diff[3] != 1 ? "s" : ""); + } + + public String getVersion() { + return version; + } + + + public List getProviders() { + return providers; + } + } + + public static class SpiInfoRepresentation implements Serializable { + private String name; + private boolean internal; + private boolean systemInfo; + private Set implementations; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isInternal() { + return internal; + } + + public void setInternal(boolean internal) { + this.internal = internal; + } + + public Set getImplementations() { + return implementations; + } + + public boolean isSystemInfo() { + return systemInfo; + } + + public void setSystemInfo(boolean systemInfo) { + this.systemInfo = systemInfo; + } + + public void setImplementations(Set implementations) { + this.implementations = implementations; + } + } + + public static class SpiImplementationRepresentation implements Serializable { + + private String name; + private Map operationalInfo; + + public SpiImplementationRepresentation(String name) { + super(); + this.name = name; + } + + public Map getOperationalInfo() { + return operationalInfo; + } + + public void setOperationalInfo(Map operationalInfo) { + this.operationalInfo = operationalInfo; + } + + public String getName() { + return name; + } + + } +} 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 2cca19a0c98..33ead317e41 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 @@ -317,13 +317,41 @@ public class AdminAPITest { Assert.assertNotNull(response); Assert.assertEquals(Version.VERSION, response.get("version")); Assert.assertNotNull(response.get("serverTime")); + Assert.assertNotNull(response.get("providers")); + Assert.assertNotNull(response.get("themes")); + Assert.assertNotNull(response.get("enums")); + + // System.out.println(response); + + } + + @Test + public void testServerInfoPage() { + + String token = createToken(); + final String authHeader = "Bearer " + token; + ClientRequestFilter authFilter = new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); + } + }; + Client client = ClientBuilder.newBuilder().register(authFilter).build(); + UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); + WebTarget target = client.target(AdminRoot.adminBaseUrl(authBase).path("serverinfopage")); + + Map response = target.request().accept("application/json").get(Map.class); + + Assert.assertNotNull(response); + Assert.assertEquals(Version.VERSION, response.get("version")); + Assert.assertNotNull(response.get("serverTime")); + Assert.assertNotNull(response.get("providers")); Assert.assertNotNull(response.get("serverStartupTime")); Assert.assertNotNull(response.get("memoryInfo")); - Assert.assertNotNull(response.get("jpaInfo")); - Assert.assertNull(response.get("mongoDbInfo")); + Assert.assertNotNull(response.get("systemInfo")); - System.out.println(response); + // System.out.println(response); } From dfb871c26a7c6dd0b6b9940f59af66b280f91831 Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Mon, 20 Jul 2015 17:11:04 +0200 Subject: [PATCH 06/14] KEYCLOAK-1542 - added system and memory info into "System Info" page --- .../admin/resources/partials/server-info.html | 75 +++++++- .../models/KeycloakSessionFactory.java | 2 + .../DefaultKeycloakSessionFactory.java | 12 ++ .../admin/ServerInfoAdminResource.java | 173 ++++++++++++++++-- 4 files changed, 249 insertions(+), 13 deletions(-) diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index 34c9a845d3a..5590f9576e1 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -8,10 +8,81 @@ Server Time - {{serverInfo.serverTime}} (update) + {{serverInfo.serverTime}} (update) + + + Server Uptime + {{serverInfo.serverUptime}} + + + Current Working Directory + {{serverInfo.systemInfo.userDir}} + + + Java Version + {{serverInfo.systemInfo.javaVersion}} + + + Java Vendor + {{serverInfo.systemInfo.javaVendor}} + + + Java Runtime + {{serverInfo.systemInfo.javaRuntime}} + + + Java VM + {{serverInfo.systemInfo.javaVm}} + + + Java VM Version + {{serverInfo.systemInfo.javaVmVersion}} + + + Java Home + {{serverInfo.systemInfo.javaHome}} + + + User Name + {{serverInfo.systemInfo.userName}} + + + User Timezone + {{serverInfo.systemInfo.userTimezone}} + + + User Locale + {{serverInfo.systemInfo.userLocale}} + + + System Encoding + {{serverInfo.systemInfo.fileEncoding}} + + + Operating System + {{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}} + + + OS Architecture + {{serverInfo.systemInfo.osArchitecture}} - + +

Java VM Memory Statistics

+ + + + + + + + + + + + + +
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
Providers 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 cbb3da22d5f..82665508c25 100755 --- a/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java +++ b/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java @@ -18,6 +18,8 @@ public interface KeycloakSessionFactory extends ProviderEventManager { ProviderFactory getProviderFactory(Class clazz, String id); List getProviderFactories(Class clazz); + + long getServerStartupTimestamp(); void close(); } diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java index e312aa01225..c5be21be10e 100755 --- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java @@ -28,6 +28,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { private Map, Map> factoriesMap = new HashMap, Map>(); protected CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); + protected long serverStartupTimestamp; + @Override public void register(ProviderEventListener listener) { listeners.add(listener); @@ -46,6 +48,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { } public void init() { + serverStartupTimestamp = System.currentTimeMillis(); + ProviderManager pm = new ProviderManager(getClass().getClassLoader(), Config.scope().getArray("providers")); for (Spi spi : ServiceLoader.load(Spi.class, getClass().getClassLoader())) { @@ -148,4 +152,12 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { return factory.getClass().getPackage().getName().startsWith("org.keycloak"); } + /** + * @return timestamp of Keycloak server startup + */ + @Override + public long getServerStartupTimestamp() { + return serverStartupTimestamp; + } + } 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 4f1c22575b0..c600b92e4b4 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,5 +1,18 @@ package org.keycloak.services.resources.admin; +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.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; @@ -24,17 +37,6 @@ 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.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; - /** * @author Stian Thorgersen */ @@ -55,6 +57,7 @@ public class ServerInfoAdminResource { ServerInfoRepresentation info = new ServerInfoRepresentation(); info.version = Version.VERSION; info.serverTime = new Date().toString(); + info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); setSocialProviders(info); setIdentityProviders(info); setThemes(info); @@ -187,12 +190,115 @@ public class ServerInfoAdminResource { info.clientImporters.add(data); } } + + public static class MemoryInfo{ + + public long getTotal(){ + return Runtime.getRuntime().maxMemory(); + } + + public String getTotalFormated(){ + return formatMemory(getTotal()); + } + + public long getFree(){ + return getTotal() - getUsed(); + } + public String getFreeFormated(){ + return formatMemory(getFree()); + } + + public long getUsed(){ + return Runtime.getRuntime().totalMemory(); + } + + public String getUsedFormated(){ + return formatMemory(getUsed()); + } + + public long getFreePercentage(){ + return getFree()*100/getTotal(); + } + + private String formatMemory(long bytes){ + if(bytes > 1024L*1024L){ + return bytes/(1024L *1024L) + " MB"; + } else if(bytes > 1024L){ + return bytes/(1024L) + " kB"; + } else { + return bytes + " B"; + } + } + + } + + public static class SystemInfo { + public String getJavaVersion(){ + return System.getProperty("java.version"); + } + + public String getJavaVendor(){ + return System.getProperty("java.vendor"); + } + + public String getJavaVm(){ + return System.getProperty("java.vm.name"); + } + + public String getJavaVmVersion(){ + return System.getProperty("java.vm.version"); + } + + public String getJavaRuntime(){ + return System.getProperty("java.runtime.name"); + } + + public String getJavaHome(){ + return System.getProperty("java.home"); + } + + public String getOsName(){ + return System.getProperty("os.name"); + } + + public String getOsArchitecture(){ + return System.getProperty("os.arch"); + } + + public String getOsVersion(){ + return System.getProperty("os.version"); + } + + public String getFileEncoding(){ + return System.getProperty("file.encoding"); + } + + public String getUserName(){ + return System.getProperty("user.name"); + } + + public String getUserDir(){ + return System.getProperty("user.dir"); + } + + public String getUserTimezone(){ + return System.getProperty("user.timezone"); + } + + public String getUserLocale(){ + return (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + } + + } + public static class ServerInfoRepresentation { private String version; private String serverTime; + + private long serverStartupTime; private Map> themes; @@ -211,10 +317,55 @@ public class ServerInfoAdminResource { public ServerInfoRepresentation() { } + + public SystemInfo getSystemInfo(){ + return new SystemInfo(); + } + + public MemoryInfo getMemoryInfo(){ + return new MemoryInfo(); + } public String getServerTime() { return serverTime; } + + /** + * @return server startup time formatted + */ + public String getServerStartupTime() { + return (new Date(serverStartupTime)).toString(); + } + + /** + * @return server uptime in millis + */ + public long getServerUptimeMillis(){ + return System.currentTimeMillis() - serverStartupTime; + } + + /** + * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" + */ + public String getServerUptime(){ + long diffInSeconds = getServerUptimeMillis()/1000; + long diff[] = new long[] { 0, 0, 0, 0 }; + /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); + /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; + /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; + /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); + + return String.format( + "%d day%s, %d hour%s, %d minute%s, %d second%s", + diff[0], + diff[0] != 1 ? "s" : "", + diff[1], + diff[1] != 1 ? "s" : "", + diff[2], + diff[2] != 1 ? "s" : "", + diff[3], + diff[3] != 1 ? "s" : ""); + } public String getVersion() { return version; From 652b2fee8688d817f47f4000c3e63fe13c3a5a6e Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Tue, 21 Jul 2015 16:09:47 +0200 Subject: [PATCH 07/14] KEYCLOAK-1542 - Server Info page extended by info about DB and MongoDB. Functional test for /serverinfo REST endpoint added. --- .../DefaultJpaConnectionProviderFactory.java | 341 ++++++++++------- .../jpa/JpaConnectionProviderFactory.java | 5 +- ...DefaultMongoConnectionFactoryProvider.java | 356 ++++++++++-------- .../mongo/MongoConnectionProviderFactory.java | 4 +- .../admin/resources/partials/server-info.html | 130 +++++-- .../provider/MonitorableProviderFactory.java | 18 + .../provider/ProviderOperationalInfo.java | 22 ++ services/pom.xml | 15 + .../admin/ServerInfoAdminResource.java | 154 ++++++-- .../testsuite/admin/AdminAPITest.java | 63 +++- 10 files changed, 720 insertions(+), 388 deletions(-) create mode 100644 model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java create mode 100644 model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java 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 61bbafa6bf9..36f3c09cce7 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,189 +1,242 @@ 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; import org.keycloak.connections.jpa.updater.JpaUpdaterProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; - -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.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; +import org.keycloak.provider.ProviderOperationalInfo; /** * @author Stian Thorgersen */ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory { - private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); + private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); - private volatile EntityManagerFactory emf; + private volatile EntityManagerFactory emf; - private Config.Scope config; + private Config.Scope config; - @Override - public JpaConnectionProvider create(KeycloakSession session) { - lazyInit(session); + private DatabaseInfo databaseInfo; - EntityManager em = emf.createEntityManager(); - em = PersistenceExceptionConverter.create(em); - session.getTransaction().enlist(new JpaKeycloakTransaction(em)); - return new DefaultJpaConnectionProvider(em); - } + @Override + public JpaConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @Override - public void close() { - if (emf != null) { - emf.close(); - } - } + EntityManager em = emf.createEntityManager(); + em = PersistenceExceptionConverter.create(em); + session.getTransaction().enlist(new JpaKeycloakTransaction(em)); + return new DefaultJpaConnectionProvider(em); + } - @Override - public String getId() { - return "default"; - } + @Override + public void close() { + if (emf != null) { + emf.close(); + } + } - @Override - public void init(Config.Scope config) { - this.config = config; - } + @Override + public String getId() { + return "default"; + } - @Override - public void postInit(KeycloakSessionFactory factory) { + @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; + private void lazyInit(KeycloakSession session) { + if (emf == null) { + synchronized (this) { + if (emf == null) { + logger.debug("Initializing JPA connections"); - String databaseSchema = config.get("databaseSchema"); + Connection connection = null; - Map properties = new HashMap(); + String databaseSchema = config.get("databaseSchema"); - String unitName = "keycloak-default"; + Map properties = new HashMap(); - 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 unitName = "keycloak-default"; - 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 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 driverDialect = config.get("driverDialect"); - if (driverDialect != null && driverDialect.length() > 0) { - properties.put("hibernate.dialect", driverDialect); - } + 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 schema = config.get("schema"); - if (schema != null) { - properties.put("hibernate.default_schema", schema); - } + String driverDialect = config.get("driverDialect"); + if (driverDialect != null && driverDialect.length() > 0) { + properties.put("hibernate.dialect", driverDialect); + } - 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; - } - } + String schema = config.get("schema"); + if (schema != null) { + properties.put("hibernate.default_schema", schema); + } - properties.put("hibernate.show_sql", config.getBoolean("showSql", false)); - properties.put("hibernate.format_sql", config.getBoolean("formatSql", true)); + 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; + } + } - if (databaseSchema != null) { - logger.trace("Updating database"); + properties.put("hibernate.show_sql", config.getBoolean("showSql", false)); + properties.put("hibernate.format_sql", config.getBoolean("formatSql", true)); - JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class); - if (updater == null) { - throw new RuntimeException("Can't update database: JPA updater provider not found"); - } + connection = getConnection(); + prepareDatabaseInfo(connection); - connection = getConnection(); + if (databaseSchema != null) { + logger.trace("Updating database"); - 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) { - } + JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class); + if (updater == null) { + throw new RuntimeException("Can't update database: JPA updater provider not found"); + } - 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); - } + 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) { + } - logger.trace("Database update completed"); - } + 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("Creating EntityManagerFactory"); - emf = Persistence.createEntityManagerFactory(unitName, properties); - logger.trace("EntityManagerFactory created"); + logger.trace("Database update completed"); + } - // Close after creating EntityManagerFactory to prevent in-mem databases from closing - if (connection != null) { - try { - connection.close(); - } catch (SQLException e) { - logger.warn(e); - } - } - } - } - } - } + logger.trace("Creating EntityManagerFactory"); + emf = Persistence.createEntityManagerFactory(unitName, properties); + logger.trace("EntityManagerFactory created"); - 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); - } - } + // 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; + } + + @Override + public boolean isOk() { + // TODO KEYCLOAK-1578 - implement operational monitoring of JPA DB connection + return true; + } + } } diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java index 1cf4a5f2026..ab2b119c29c 100644 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java @@ -1,9 +1,10 @@ package org.keycloak.connections.jpa; -import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.MonitorableProviderFactory; /** * @author Stian Thorgersen */ -public interface JpaConnectionProviderFactory extends ProviderFactory { +public interface JpaConnectionProviderFactory extends MonitorableProviderFactory { + } 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 36be680a668..c8d1cbaed4a 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,11 @@ package org.keycloak.connections.mongo; -import com.mongodb.DB; -import com.mongodb.MongoClient; -import com.mongodb.MongoClientOptions; -import com.mongodb.MongoCredential; -import com.mongodb.ServerAddress; +import java.lang.reflect.Method; +import java.net.UnknownHostException; +import java.util.Collections; + +import javax.net.ssl.SSLSocketFactory; + import org.jboss.logging.Logger; import org.keycloak.Config; import org.keycloak.connections.mongo.api.MongoStore; @@ -13,198 +14,225 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati import org.keycloak.connections.mongo.updater.MongoUpdaterProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.ProviderOperationalInfo; -import javax.net.ssl.SSLSocketFactory; -import java.lang.reflect.Method; -import java.net.UnknownHostException; -import java.util.Collections; +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; /** * @author Stian Thorgersen */ 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", - }; + // 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 static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class); - private volatile MongoClient client; + private volatile MongoClient client; - private MongoStore mongoStore; - private DB db; - protected Config.Scope config; + private MongoStore mongoStore; + private DB db; + protected Config.Scope config; - @Override - public MongoConnectionProvider create(KeycloakSession session) { - lazyInit(session); + private MongoDbInfo mongoDbInfo; - TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore); - session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext)); - return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext); - } + @Override + public MongoConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @Override - public void init(Config.Scope config) { - this.config = config; - } + TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore); + session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext)); + return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext); + } - @Override - public void postInit(KeycloakSessionFactory factory) { + @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(); + 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 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); + 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"); - } + 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); - } - } + 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); - } - } - } - } - } + 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; - } + 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 void close() { + if (client != null) { + client.close(); + } + } - @Override - public String getId() { - return "default"; - } + @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"); + /** + * 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"); + String user = config.get("user"); + String password = config.get("password"); - MongoClientOptions clientOptions = getClientOptions(); + 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); - } + 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); + } - logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); - return client; - } + mongoDbInfo = new MongoDbInfo(); + mongoDbInfo.driverVersion = client.getVersion(); + mongoDbInfo.address = client.getAddress().toString(); + mongoDbInfo.database = dbName; + mongoDbInfo.user = user; - 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()); - } + logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); + return client; + } - return builder.build(); - } + 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()); + } - 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); - } - } - } + return builder.build(); + } - 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); - } - } - } + 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; + + @Override + public boolean isOk() { + // TODO KEYCLOAK-1578 - implement operational monitoring of Mongo DB connection + return true; + } + + public String getAddress() { + return address; + } + + public String getDatabase() { + return database; + } + + public String getDriverVersion() { + return driverVersion; + } + + public String getUser() { + return user; + } + } } diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java index e787ce63825..3b3a00e5602 100644 --- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java +++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java @@ -1,9 +1,9 @@ package org.keycloak.connections.mongo; -import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.MonitorableProviderFactory; /** * @author Stian Thorgersen */ -public interface MongoConnectionProviderFactory extends ProviderFactory { +public interface MongoConnectionProviderFactory extends MonitorableProviderFactory { } diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index 5590f9576e1..f4e4c6dcf26 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -1,21 +1,47 @@
-

Server Info

+

Server Info

- +
+ + + + + + + + + + + + +
Keycloak Version{{serverInfo.version}}
Server Time{{serverInfo.serverTime}} (update)
Server Uptime{{serverInfo.serverUptime}}
+ +
+ Java VM Memory Statistics +
+ + + + + + + + + + + + + +
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
+
+
+ +
+ System Info +
+ - - - - - - - - - - - - - + @@ -66,23 +92,59 @@ -
Version{{serverInfo.version}}
Server Time{{serverInfo.serverTime}} (update)
Server Uptime{{serverInfo.serverUptime}}
Current Working DirectoryCurrent Working Directory {{serverInfo.systemInfo.userDir}}
OS Architecture {{serverInfo.systemInfo.osArchitecture}}
- -

Java VM Memory Statistics

- - - - - - - - - - - - - -
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
+ +
+
+ + +
+ Database Info +
+ + + + + + + + + + + + + + + + + +
Database URL{{serverInfo.jpaInfo.jdbcUrl}}
Database User{{serverInfo.jpaInfo.databaseUser}}
Database Type{{serverInfo.jpaInfo.databaseProduct}}
Database Driver{{serverInfo.jpaInfo.databaseDriver}}
+
+
+ +
+ Mongo DB Info +
+ + + + + + + + + + + + + + + + + +
Address{{serverInfo.mongoDbInfo.address}}
Database{{serverInfo.mongoDbInfo.database}}
User{{serverInfo.mongoDbInfo.user}}
Driver Version{{serverInfo.mongoDbInfo.driverVersion}}
+
+
+
Providers @@ -93,7 +155,7 @@ - + @@ -117,7 +179,7 @@
SPISPI Providers
- + diff --git a/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java new file mode 100644 index 00000000000..7b9c95c9218 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java @@ -0,0 +1,18 @@ +package org.keycloak.provider; + +/** + * Provider factory for provider which is monitorable. It means some info about it can be shown on "Server Info" page or accessed over Operational monitoring endpoint. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public interface MonitorableProviderFactory extends ProviderFactory { + + /** + * Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc). + * Is used to be shown on "Server Info" page or in Operational monitoring endpoint. + * + * @return extendion of {@link ProviderOperationalInfo} + */ + public ProviderOperationalInfo getOperationalInfo(); + +} diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java new file mode 100644 index 00000000000..ca3e8a6849a --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java @@ -0,0 +1,22 @@ +package org.keycloak.provider; + +import java.io.Serializable; + +/** + * Operational info about given Provider. + * Contains info about Provider that can be shown on "Server Info" page or accessed over Operational monitoring endpoint. + * + * @author Vlastimil Elias (velias at redhat dot com) + * @see MonitorableProviderFactory + */ +public interface ProviderOperationalInfo extends Serializable { + + /** + * Return true if provider is OK from operation point of view. It means it is able to perform necessary work. + * It can return false for example if remote DB of JPA provider is not available, or LDAP server of LDAP based user federation provider is not available. + * + * @return true if provider is OK to perform his operation. + */ + boolean isOk(); + +} diff --git a/services/pom.xml b/services/pom.xml index da71e9ae6f6..16fef06d5cb 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -39,6 +39,21 @@ keycloak-connections-http-client provided + + org.keycloak + keycloak-connections-jpa + provided + + + org.hibernate + hibernate-entitymanager + provided + + + org.keycloak + keycloak-connections-mongo + provided + org.keycloak keycloak-forms-common-freemarker 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 c600b92e4b4..91610db0c43 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,5 +1,6 @@ package org.keycloak.services.resources.admin; +import java.io.Serializable; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -13,9 +14,13 @@ 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; import org.keycloak.broker.provider.IdentityProviderFactory; +import org.keycloak.connections.jpa.JpaConnectionProvider; +import org.keycloak.connections.mongo.DefaultMongoConnectionFactoryProvider.MongoDbInfo; +import org.keycloak.connections.mongo.MongoConnectionProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; import org.keycloak.events.admin.OperationType; @@ -29,8 +34,10 @@ import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.ProtocolMapper; +import org.keycloak.provider.MonitorableProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.ProviderOperationalInfo; import org.keycloak.provider.Spi; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -41,6 +48,8 @@ import org.keycloak.social.SocialIdentityProvider; * @author Stian Thorgersen */ public class ServerInfoAdminResource { + + private static final Logger logger = Logger.getLogger(ServerInfoAdminResource.class); private static final Map> ENUMS = createEnumsMap(EventType.class, OperationType.class); @@ -58,6 +67,8 @@ public class ServerInfoAdminResource { info.version = Version.VERSION; info.serverTime = new Date().toString(); info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); + info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); + info.systemInfo = (new SystemInfo()).init(); setSocialProviders(info); setIdentityProviders(info); setThemes(info); @@ -68,6 +79,21 @@ public class ServerInfoAdminResource { setProtocolMapperTypes(info); setBuiltinProtocolMappers(info); info.setEnums(ENUMS); + + ProviderFactory jpf = session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class); + if(jpf!=null && jpf instanceof MonitorableProviderFactory){ + info.jpaInfo = ((MonitorableProviderFactory)jpf).getOperationalInfo(); + } else { + logger.debug("JPA provider not found or is not monitorable"); + } + + ProviderFactory mpf = session.getKeycloakSessionFactory().getProviderFactory(MongoConnectionProvider.class); + if(mpf!=null && mpf instanceof MonitorableProviderFactory){ + info.mongoDbInfo = ((MonitorableProviderFactory)mpf).getOperationalInfo(); + } else { + logger.debug("Mongo provider not found or is not monitorable"); + } + return info; } @@ -191,10 +217,28 @@ public class ServerInfoAdminResource { } } - public static class MemoryInfo{ + public static class MemoryInfo implements Serializable { + + protected long total; + + protected long used; + + public MemoryInfo(){ + } + + /** + * Fill object fwith info. + * @param runtime used to get memory info from. + * @return itself for chaining + */ + public MemoryInfo init(Runtime runtime){ + total = runtime.maxMemory(); + used = runtime.totalMemory() - runtime.freeMemory(); + return this; + } public long getTotal(){ - return Runtime.getRuntime().maxMemory(); + return total; } public String getTotalFormated(){ @@ -210,7 +254,7 @@ public class ServerInfoAdminResource { } public long getUsed(){ - return Runtime.getRuntime().totalMemory(); + return used; } public String getUsedFormated(){ @@ -218,7 +262,7 @@ public class ServerInfoAdminResource { } public long getFreePercentage(){ - return getFree()*100/getTotal(); + return getFree() * 100 / getTotal(); } private String formatMemory(long bytes){ @@ -233,71 +277,109 @@ public class ServerInfoAdminResource { } - public static class SystemInfo { + public static class SystemInfo implements Serializable { + + protected String javaVersion; + protected String javaVendor; + protected String javaVm; + protected String javaVmVersion; + protected String javaRuntime; + protected String javaHome; + protected String osName; + protected String osArchitecture; + protected String osVersion; + protected String fileEncoding; + protected String userName; + protected String userDir; + protected String userTimezone; + protected String userLocale; + + public SystemInfo() { + } + + /** + * Fill object with info about current system loaded from {@link System} properties. + * @return object itself for chaining + */ + protected SystemInfo init(){ + javaVersion = System.getProperty("java.version"); + javaVendor = System.getProperty("java.vendor"); + javaVm = System.getProperty("java.vm.name"); + javaVmVersion = System.getProperty("java.vm.version"); + javaRuntime = System.getProperty("java.runtime.name"); + javaHome = System.getProperty("java.home"); + osName = System.getProperty("os.name"); + osArchitecture = System.getProperty("os.arch"); + osVersion = System.getProperty("os.version"); + fileEncoding = System.getProperty("file.encoding"); + userName = System.getProperty("user.name"); + userDir = System.getProperty("user.dir"); + userTimezone = System.getProperty("user.timezone"); + userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + return this; + } + public String getJavaVersion(){ - return System.getProperty("java.version"); + return javaVersion; } public String getJavaVendor(){ - return System.getProperty("java.vendor"); + return javaVendor; } public String getJavaVm(){ - return System.getProperty("java.vm.name"); + return javaVm; } public String getJavaVmVersion(){ - return System.getProperty("java.vm.version"); + return javaVmVersion; } public String getJavaRuntime(){ - return System.getProperty("java.runtime.name"); + return javaRuntime; } public String getJavaHome(){ - return System.getProperty("java.home"); + return javaHome; } public String getOsName(){ - return System.getProperty("os.name"); + return osName; } public String getOsArchitecture(){ - return System.getProperty("os.arch"); + return osArchitecture; } public String getOsVersion(){ - return System.getProperty("os.version"); + return osVersion; } public String getFileEncoding(){ - return System.getProperty("file.encoding"); + return fileEncoding; } public String getUserName(){ - return System.getProperty("user.name"); + return userName; } public String getUserDir(){ - return System.getProperty("user.dir"); + return userDir; } public String getUserTimezone(){ - return System.getProperty("user.timezone"); + return userTimezone; } public String getUserLocale(){ - return (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + return userLocale; } - } - public static class ServerInfoRepresentation { + public static class ServerInfoRepresentation implements Serializable { private String version; - private String serverTime; - private long serverStartupTime; private Map> themes; @@ -314,26 +396,44 @@ public class ServerInfoAdminResource { private Map> builtinProtocolMappers; private Map> enums; + + private MemoryInfo memoryInfo; + private SystemInfo systemInfo; + + private ProviderOperationalInfo jpaInfo; + private ProviderOperationalInfo mongoDbInfo; public ServerInfoRepresentation() { } public SystemInfo getSystemInfo(){ - return new SystemInfo(); + return systemInfo; } public MemoryInfo getMemoryInfo(){ - return new MemoryInfo(); + return memoryInfo; + } + + public ProviderOperationalInfo getJpaInfo() { + return jpaInfo; + } + + public ProviderOperationalInfo getMongoDbInfo() { + return mongoDbInfo; } public String getServerTime() { return serverTime; } + public long getServerStartupTime() { + return serverStartupTime; + } + /** * @return server startup time formatted */ - public String getServerStartupTime() { + public String getServerStartupTimeFormatted() { return (new Date(serverStartupTime)).toString(); } @@ -420,7 +520,7 @@ public class ServerInfoAdminResource { } } - public static class SpiInfoRepresentation { + public static class SpiInfoRepresentation implements Serializable { private String name; private boolean internal; private Set implementations; 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 3bde1cb7406..85a81bbbebd 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,10 +21,27 @@ */ 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; import org.keycloak.Config; +import org.keycloak.Version; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.Constants; @@ -40,22 +57,8 @@ 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.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.Set; +import org.keycloak.testsuite.rule.AbstractKeycloakRule; /** * Tests Undertow Adapter @@ -295,4 +298,34 @@ public class AdminAPITest { testCreateRealm("/admin-test/testrealm.json"); } + @Test + public void testServerInfo() { + + String token = createToken(); + final String authHeader = "Bearer " + token; + ClientRequestFilter authFilter = new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); + } + }; + Client client = ClientBuilder.newBuilder().register(authFilter).build(); + UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); + WebTarget target = client.target(AdminRoot.adminBaseUrl(authBase).path("serverinfo")); + + Map response = target.request().accept("application/json").get(Map.class); + + Assert.assertNotNull(response); + Assert.assertEquals(Version.VERSION, response.get("version")); + Assert.assertNotNull(response.get("serverTime")); + Assert.assertNotNull(response.get("serverStartupTime")); + + Assert.assertNotNull(response.get("memoryInfo")); + Assert.assertNotNull(response.get("jpaInfo")); + Assert.assertNull(response.get("mongoDbInfo")); + + System.out.println(response); + + } + } From 79c1d7bafa3eb84bf3927d78d4c394dda3cd6776 Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Wed, 22 Jul 2015 13:35:56 +0200 Subject: [PATCH 08/14] KEYCLOAK-1542 - code cleanup ahead of PR --- .../jpa/DefaultJpaConnectionProviderFactory.java | 6 ------ .../mongo/DefaultMongoConnectionFactoryProvider.java | 6 ------ .../org/keycloak/provider/ProviderOperationalInfo.java | 8 -------- .../services/resources/admin/ServerInfoAdminResource.java | 1 - 4 files changed, 21 deletions(-) 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 36f3c09cce7..1795cd13c5f 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 @@ -231,12 +231,6 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide public String getDatabaseProduct() { return databaseProduct; } - - @Override - public boolean isOk() { - // TODO KEYCLOAK-1578 - implement operational monitoring of JPA DB connection - return true; - } } } 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 c8d1cbaed4a..248b880be6c 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 @@ -212,12 +212,6 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro public String driverVersion; public String user; - @Override - public boolean isOk() { - // TODO KEYCLOAK-1578 - implement operational monitoring of Mongo DB connection - return true; - } - public String getAddress() { return address; } diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java index ca3e8a6849a..e37544d2768 100644 --- a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java +++ b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java @@ -11,12 +11,4 @@ import java.io.Serializable; */ public interface ProviderOperationalInfo extends Serializable { - /** - * Return true if provider is OK from operation point of view. It means it is able to perform necessary work. - * It can return false for example if remote DB of JPA provider is not available, or LDAP server of LDAP based user federation provider is not available. - * - * @return true if provider is OK to perform his operation. - */ - boolean isOk(); - } 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 91610db0c43..dbb0ff0c8f1 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 @@ -19,7 +19,6 @@ import org.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; import org.keycloak.connections.jpa.JpaConnectionProvider; -import org.keycloak.connections.mongo.DefaultMongoConnectionFactoryProvider.MongoDbInfo; import org.keycloak.connections.mongo.MongoConnectionProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; From 7e41b8df27d4fcbd2e02941fd8ba229a538d71e5 Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Wed, 22 Jul 2015 14:28:08 +0200 Subject: [PATCH 09/14] KEYCLOAK-1542 - code formatting cleanup --- .../DefaultJpaConnectionProviderFactory.java | 385 +++++++++--------- ...DefaultMongoConnectionFactoryProvider.java | 377 +++++++++-------- .../admin/ServerInfoAdminResource.java | 28 +- .../testsuite/admin/AdminAPITest.java | 33 +- 4 files changed, 420 insertions(+), 403 deletions(-) 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 1795cd13c5f..aac1cdebd47 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 Stian Thorgersen */ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory { - private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); + private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class); - private volatile EntityManagerFactory emf; + private volatile EntityManagerFactory emf; - private Config.Scope config; + private Config.Scope config; + + private DatabaseInfo databaseInfo; - private DatabaseInfo databaseInfo; + @Override + public JpaConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @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); + } - 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 void close() { - if (emf != null) { - emf.close(); - } - } + @Override + public String getId() { + return "default"; + } - @Override - public String getId() { - return "default"; - } + @Override + public void init(Config.Scope config) { + this.config = config; + } - @Override - public void init(Config.Scope config) { - this.config = config; - } + @Override + public void postInit(KeycloakSessionFactory factory) { - @Override - public void postInit(KeycloakSessionFactory factory) { + } - } + private void lazyInit(KeycloakSession session) { + if (emf == null) { + synchronized (this) { + if (emf == null) { + logger.debug("Initializing JPA connections"); - private void lazyInit(KeycloakSession session) { - if (emf == null) { - synchronized (this) { - if (emf == null) { - logger.debug("Initializing JPA connections"); + Connection connection = null; - Connection connection = null; + String databaseSchema = config.get("databaseSchema"); - String databaseSchema = config.get("databaseSchema"); + Map properties = new HashMap(); - Map properties = new HashMap(); + String unitName = "keycloak-default"; - 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 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 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 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); + } - 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; + } + } - 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)); - 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"); - connection = getConnection(); - prepareDatabaseInfo(connection); + } 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()); + } + } - if (databaseSchema != null) { - logger.trace("Updating database"); + 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; + } - JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class); - if (updater == null) { - throw new RuntimeException("Can't update database: JPA updater provider not found"); - } + public static class DatabaseInfo implements ProviderOperationalInfo { + protected String jdbcUrl; + protected String databaseUser; + protected String databaseProduct; + protected String databaseDriver; - 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) { - } + public String getJdbcUrl() { + return jdbcUrl; + } - 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); - } + public String getDatabaseDriver() { + return databaseDriver; + } - logger.trace("Database update completed"); - } + public String getDatabaseUser() { + return databaseUser; + } - 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; - } - } + 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 248b880be6c..2df4b853630 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 Stian Thorgersen */ 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", }; + // 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 static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class); - private volatile MongoClient client; + private volatile MongoClient client; - private MongoStore mongoStore; - private DB db; - protected Config.Scope config; + private MongoStore mongoStore; + private DB db; + protected Config.Scope config; + + private MongoDbInfo mongoDbInfo; - private MongoDbInfo mongoDbInfo; + @Override + public MongoConnectionProvider create(KeycloakSession session) { + lazyInit(session); - @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); + } - 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 init(Config.Scope config) { - this.config = config; - } + @Override + public void postInit(KeycloakSessionFactory factory) { - @Override - public void postInit(KeycloakSessionFactory factory) { + } - } - private void lazyInit(KeycloakSession session) { - if (client == null) { - synchronized (this) { - if (client == null) { - try { - this.client = createMongoClient(); + 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 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); + 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"); - } + 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); - } - } + 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); - } - } - } - } - } + 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; - } + 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 void close() { + if (client != null) { + client.close(); + } + } - @Override - public String getId() { - return "default"; - } + @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"); + /** + * 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"); + String user = config.get("user"); + String password = config.get("password"); - MongoClientOptions clientOptions = getClientOptions(); + 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); - } + 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; + } - mongoDbInfo = new MongoDbInfo(); - mongoDbInfo.driverVersion = client.getVersion(); - mongoDbInfo.address = client.getAddress().toString(); - mongoDbInfo.database = dbName; - mongoDbInfo.user = user; + 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()); + } - logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); - return client; - } + return builder.build(); + } - 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()); - } + 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); + } + } + } - return builder.build(); - } + 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; + } - 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); - } - } - } + public static class MongoDbInfo implements ProviderOperationalInfo { - 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); - } - } - } + public String address; + public String database; + public String driverVersion; + public String user; - @Override - public ProviderOperationalInfo getOperationalInfo() { - return mongoDbInfo; - } + public String getAddress() { + return address; + } - public static class MongoDbInfo implements ProviderOperationalInfo { + public String getDatabase() { + return database; + } - 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; - } - } + 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 dbb0ff0c8f1..3b69304b065 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 Stian Thorgersen */ @@ -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 85a81bbbebd..2cca19a0c98 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 From ee57c797849edf25504ab83c3ecfea66b894fab9 Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Thu, 23 Jul 2015 16:39:27 +0200 Subject: [PATCH 10/14] KEYCLOAK-1542 - rewrote showing info from providers to be generic --- .../DefaultJpaConnectionProviderFactory.java | 48 +-- .../jpa/JpaConnectionProviderFactory.java | 4 +- ...DefaultMongoConnectionFactoryProvider.java | 43 +- .../mongo/MongoConnectionProviderFactory.java | 4 +- .../theme/base/admin/resources/js/app.js | 10 +- .../admin/resources/js/controllers/realm.js | 7 + .../theme/base/admin/resources/js/loaders.js | 4 + .../theme/base/admin/resources/js/services.js | 3 + .../admin/resources/partials/server-info.html | 118 +++--- .../provider/MonitorableProviderFactory.java | 18 - .../provider/ProviderOperationalInfo.java | 14 - .../ServerInfoAwareProviderFactory.java | 20 + services/pom.xml | 15 - .../services/resources/admin/AdminRoot.java | 26 ++ .../admin/ServerInfoAdminResource.java | 254 +----------- .../admin/ServerInfoPageAdminResource.java | 375 ++++++++++++++++++ .../testsuite/admin/AdminAPITest.java | 34 +- 17 files changed, 556 insertions(+), 441 deletions(-) delete mode 100644 model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java delete mode 100644 model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java create mode 100644 model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java 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 aac1cdebd47..a79c82b2286 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 @@ -6,20 +6,19 @@ import org.keycloak.Config; import org.keycloak.connections.jpa.updater.JpaUpdaterProvider; 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.LinkedHashMap; import java.util.Map; /** @@ -33,7 +32,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide private Config.Scope config; - private DatabaseInfo databaseInfo; + private Map operationalInfo; @Override public JpaConnectionProvider create(KeycloakSession session) { @@ -127,7 +126,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide connection = getConnection(); try{ - prepareDatabaseInfo(connection); + prepareOperationalInfo(connection); if (databaseSchema != null) { logger.trace("Updating database"); @@ -180,16 +179,16 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide } } - protected void prepareDatabaseInfo(Connection connection) { + protected void prepareOperationalInfo(Connection connection) { try { - databaseInfo = new DatabaseInfo(); + operationalInfo = new LinkedHashMap<>(); DatabaseMetaData md = connection.getMetaData(); - databaseInfo.databaseDriver = md.getDriverName() + " " + md.getDriverVersion(); - databaseInfo.databaseProduct = md.getDatabaseProductName() + " " + md.getDatabaseProductVersion(); - databaseInfo.databaseUser = md.getUserName(); - databaseInfo.jdbcUrl = md.getURL(); + operationalInfo.put("databaseUrl",md.getURL()); + operationalInfo.put("databaseUser", md.getUserName()); + operationalInfo.put("databaseProduct", md.getDatabaseProductName() + " " + md.getDatabaseProductVersion()); + operationalInfo.put("databaseDriver", md.getDriverName() + " " + md.getDriverVersion()); } catch (SQLException e) { - logger.warn("Unable to get database info due " + e.getMessage()); + logger.warn("Unable to prepare operational info due database exception: " + e.getMessage()); } } @@ -209,31 +208,8 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide } @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; - } + public Map getOperationalInfo() { + return operationalInfo; } } diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java index ab2b119c29c..288e403335a 100644 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java @@ -1,10 +1,10 @@ package org.keycloak.connections.jpa; -import org.keycloak.provider.MonitorableProviderFactory; +import org.keycloak.provider.ServerInfoAwareProviderFactory; /** * @author Stian Thorgersen */ -public interface JpaConnectionProviderFactory extends MonitorableProviderFactory { +public interface JpaConnectionProviderFactory extends ServerInfoAwareProviderFactory { } 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 2df4b853630..8da15b69c12 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 @@ -14,13 +14,13 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati import org.keycloak.connections.mongo.updater.MongoUpdaterProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.provider.ProviderOperationalInfo; import javax.net.ssl.SSLSocketFactory; - import java.lang.reflect.Method; import java.net.UnknownHostException; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; /** * @author Stian Thorgersen @@ -61,7 +61,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro private DB db; protected Config.Scope config; - private MongoDbInfo mongoDbInfo; + private Map operationalInfo; @Override public MongoConnectionProvider create(KeycloakSession session) { @@ -165,11 +165,11 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro 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; + operationalInfo = new LinkedHashMap<>(); + operationalInfo.put("mongoServerAddress", client.getAddress().toString()); + operationalInfo.put("mongoDatabaseName", dbName); + operationalInfo.put("mongoUser", user); + operationalInfo.put("mongoDriverVersion", client.getVersion()); logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName); return client; @@ -219,31 +219,8 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro } @Override - public ProviderOperationalInfo getOperationalInfo() { - return mongoDbInfo; + public Map getOperationalInfo() { + return operationalInfo; } - 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/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java index 3b3a00e5602..bce5fe4b9cf 100644 --- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java +++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java @@ -1,9 +1,9 @@ package org.keycloak.connections.mongo; -import org.keycloak.provider.MonitorableProviderFactory; +import org.keycloak.provider.ServerInfoAwareProviderFactory; /** * @author Stian Thorgersen */ -public interface MongoConnectionProviderFactory extends MonitorableProviderFactory { +public interface MongoConnectionProviderFactory extends ServerInfoAwareProviderFactory { } diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js index 8fb7c36fed2..4f02ce6b486 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js @@ -1133,7 +1133,13 @@ module.config([ '$routeProvider', function($routeProvider) { controller : 'AuthenticationConfigCreateCtrl' }) .when('/server-info', { - templateUrl : resourceUrl + '/partials/server-info.html' + templateUrl : resourceUrl + '/partials/server-info.html', + resolve : { + serverInfoPage : function(ServerInfoPageLoader) { + return ServerInfoPageLoader(); + } + }, + controller : 'ServerInfoPageCtrl' }) .when('/logout', { templateUrl : resourceUrl + '/partials/home.html', @@ -1867,4 +1873,4 @@ module.directive( 'kcOpen', function ( $location ) { }); }); }; -}); \ No newline at end of file +}); diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js index 85ad18b5c25..5c5e0232c89 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js @@ -125,6 +125,13 @@ module.controller('RealmTabCtrl', function(Dialog, $scope, Current, Realm, Notif }; }); +module.controller('ServerInfoPageCtrl', function($scope, ServerInfoPage) { + $scope.serverInfoPage = ServerInfoPage.get(); + $scope.serverInfoPageUpdate = function() { + $scope.serverInfoPage = ServerInfoPage.get(); + }; +}); + module.controller('RealmListCtrl', function($scope, Realm, Current) { $scope.realms = Realm.query(); Current.realms = $scope.realms; diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js index 37a95663975..2e65b3c7124 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js @@ -39,6 +39,10 @@ module.factory('ServerInfoLoader', function(Loader, ServerInfo, $q) { return Loader.get(ServerInfo); }); +module.factory('ServerInfoPageLoader', function(Loader, ServerInfoPage, $q) { + return Loader.get(ServerInfoPage); +}); + module.factory('RealmLoader', function(Loader, Realm, $route, $q) { return Loader.get(Realm, function() { return { diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js index 3763ba9a9fb..b5d8c330f3d 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js @@ -219,6 +219,9 @@ module.factory('ServerInfo', function($resource) { return $resource(authUrl + '/admin/serverinfo'); }); +module.factory('ServerInfoPage', function($resource) { + return $resource(authUrl + '/admin/serverinfopage'); +}); module.factory('ClientProtocolMapper', function($resource) { diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index f4e4c6dcf26..0dfac4cb9ac 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -4,15 +4,15 @@
SPISPI Providers
- + - + - +
Keycloak Version{{serverInfo.version}}{{serverInfoPage.version}}
Server Time{{serverInfo.serverTime}} (update){{serverInfoPage.serverTime}} (update)
Server Uptime{{serverInfo.serverUptime}}{{serverInfoPage.serverUptime}}
@@ -22,15 +22,15 @@ - + - + - +
Total Memory{{serverInfo.memoryInfo.totalFormated}}{{serverInfoPage.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%){{serverInfoPage.memoryInfo.freeFormated}} ({{serverInfoPage.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}{{serverInfoPage.memoryInfo.usedFormated}}
@@ -42,109 +42,73 @@ - + - + - + - + - + - + - + - + - + - + - + - + - +
Current Working Directory{{serverInfo.systemInfo.userDir}}{{serverInfoPage.systemInfo.userDir}}
Java Version{{serverInfo.systemInfo.javaVersion}}{{serverInfoPage.systemInfo.javaVersion}}
Java Vendor{{serverInfo.systemInfo.javaVendor}}{{serverInfoPage.systemInfo.javaVendor}}
Java Runtime{{serverInfo.systemInfo.javaRuntime}}{{serverInfoPage.systemInfo.javaRuntime}}
Java VM{{serverInfo.systemInfo.javaVm}}{{serverInfoPage.systemInfo.javaVm}}
Java VM Version{{serverInfo.systemInfo.javaVmVersion}}{{serverInfoPage.systemInfo.javaVmVersion}}
Java Home{{serverInfo.systemInfo.javaHome}}{{serverInfoPage.systemInfo.javaHome}}
User Name{{serverInfo.systemInfo.userName}}{{serverInfoPage.systemInfo.userName}}
User Timezone{{serverInfo.systemInfo.userTimezone}}{{serverInfoPage.systemInfo.userTimezone}}
User Locale{{serverInfo.systemInfo.userLocale}}{{serverInfoPage.systemInfo.userLocale}}
System Encoding{{serverInfo.systemInfo.fileEncoding}}{{serverInfoPage.systemInfo.fileEncoding}}
Operating System{{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}}{{serverInfoPage.systemInfo.osName}} {{serverInfoPage.systemInfo.osVersion}}
OS Architecture{{serverInfo.systemInfo.osArchitecture}}{{serverInfoPage.systemInfo.osArchitecture}}
-
+
Database Info
- - - - - - - - - - - - - - - + + +
Database URL{{serverInfo.jpaInfo.jdbcUrl}}
Database User{{serverInfo.jpaInfo.databaseUser}}
Database Type{{serverInfo.jpaInfo.databaseProduct}}
Database Driver{{serverInfo.jpaInfo.databaseDriver}}
{{key}}{{value}}
-
- Mongo DB Info -
- - - - - - - - - - - - - - - - - -
Address{{serverInfo.mongoDbInfo.address}}
Database{{serverInfo.mongoDbInfo.database}}
User{{serverInfo.mongoDbInfo.user}}
Driver Version{{serverInfo.mongoDbInfo.driverVersion}}
-
-
-
Providers @@ -160,11 +124,23 @@ - + {{spi.name}} -
- {{provider}} +
+ {{provider.name}} + + + + + + + +
{{key}}{{value}}
+
@@ -184,11 +160,23 @@ - + {{spi.name}} -
- {{provider}} +
+ {{provider.name}} + + + + + + + +
{{key}}{{value}}
+
diff --git a/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java deleted file mode 100644 index 7b9c95c9218..00000000000 --- a/model/api/src/main/java/org/keycloak/provider/MonitorableProviderFactory.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.keycloak.provider; - -/** - * Provider factory for provider which is monitorable. It means some info about it can be shown on "Server Info" page or accessed over Operational monitoring endpoint. - * - * @author Vlastimil Elias (velias at redhat dot com) - */ -public interface MonitorableProviderFactory extends ProviderFactory { - - /** - * Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc). - * Is used to be shown on "Server Info" page or in Operational monitoring endpoint. - * - * @return extendion of {@link ProviderOperationalInfo} - */ - public ProviderOperationalInfo getOperationalInfo(); - -} diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java b/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java deleted file mode 100644 index e37544d2768..00000000000 --- a/model/api/src/main/java/org/keycloak/provider/ProviderOperationalInfo.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.keycloak.provider; - -import java.io.Serializable; - -/** - * Operational info about given Provider. - * Contains info about Provider that can be shown on "Server Info" page or accessed over Operational monitoring endpoint. - * - * @author Vlastimil Elias (velias at redhat dot com) - * @see MonitorableProviderFactory - */ -public interface ProviderOperationalInfo extends Serializable { - -} diff --git a/model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java new file mode 100644 index 00000000000..97d17b1dcc0 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java @@ -0,0 +1,20 @@ +package org.keycloak.provider; + +import java.util.Map; + +/** + * Marker interface for ProviderFactory of Provider which wants to show some info on "Server Info" page in Admin console. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public interface ServerInfoAwareProviderFactory extends ProviderFactory { + + /** + * Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc) which is + * shown on "Server Info" page. + * + * @return Map with keys describing value and relevant values itself + */ + public Map getOperationalInfo(); + +} diff --git a/services/pom.xml b/services/pom.xml index 16fef06d5cb..da71e9ae6f6 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -39,21 +39,6 @@ keycloak-connections-http-client provided - - org.keycloak - keycloak-connections-jpa - provided - - - org.hibernate - hibernate-entitymanager - provided - - - org.keycloak - keycloak-connections-mongo - provided - org.keycloak keycloak-forms-common-freemarker diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java index e1d1fa3c48a..6b3ca3eafa7 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java @@ -218,6 +218,32 @@ public class AdminRoot { return adminResource; } + /** + * Operational information about the server for "Server Info" page + * + * @param headers + * @return + */ + @Path("serverinfopage") + public ServerInfoPageAdminResource getServerInfoPage(@Context final HttpHeaders headers) { + handlePreflightRequest(); + + AdminAuth auth = authenticateRealmAdminRequest(headers); + if (!isAdmin(auth)) { + throw new ForbiddenException(); + } + + if (auth != null) { + logger.debug("authenticated admin access for: " + auth.getUser().getUsername()); + } + + Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response); + + ServerInfoPageAdminResource adminResource = new ServerInfoPageAdminResource(); + ResteasyProviderFactory.getInstance().injectProperties(adminResource); + return adminResource; + } + protected boolean isAdmin(AdminAuth auth) { RealmManager realmManager = new RealmManager(session); 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 3b69304b065..4f1c22575b0 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,11 +1,8 @@ package org.keycloak.services.resources.admin; -import org.jboss.logging.Logger; import org.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; -import org.keycloak.connections.jpa.JpaConnectionProvider; -import org.keycloak.connections.mongo.MongoConnectionProvider; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; import org.keycloak.events.admin.OperationType; @@ -19,10 +16,8 @@ import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.ProtocolMapper; -import org.keycloak.provider.MonitorableProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; -import org.keycloak.provider.ProviderOperationalInfo; import org.keycloak.provider.Spi; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -31,13 +26,11 @@ 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; @@ -46,8 +39,6 @@ import java.util.Set; * @author Stian Thorgersen */ public class ServerInfoAdminResource { - - private static final Logger logger = Logger.getLogger(ServerInfoAdminResource.class); private static final Map> ENUMS = createEnumsMap(EventType.class, OperationType.class); @@ -64,9 +55,6 @@ public class ServerInfoAdminResource { ServerInfoRepresentation info = new ServerInfoRepresentation(); info.version = Version.VERSION; info.serverTime = new Date().toString(); - info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); - info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); - info.systemInfo = (new SystemInfo()).init(); setSocialProviders(info); setIdentityProviders(info); setThemes(info); @@ -77,21 +65,6 @@ public class ServerInfoAdminResource { setProtocolMapperTypes(info); setBuiltinProtocolMappers(info); info.setEnums(ENUMS); - - ProviderFactory jpf = session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class); - if(jpf!=null && jpf instanceof MonitorableProviderFactory){ - info.jpaInfo = ((MonitorableProviderFactory)jpf).getOperationalInfo(); - } else { - logger.debug("JPA provider not found or is not monitorable"); - } - - ProviderFactory mpf = session.getKeycloakSessionFactory().getProviderFactory(MongoConnectionProvider.class); - if(mpf!=null && mpf instanceof MonitorableProviderFactory){ - info.mongoDbInfo = ((MonitorableProviderFactory)mpf).getOperationalInfo(); - } else { - logger.debug("Mongo provider not found or is not monitorable"); - } - return info; } @@ -214,170 +187,12 @@ public class ServerInfoAdminResource { info.clientImporters.add(data); } } - - public static class MemoryInfo implements Serializable { - - protected long total; - protected long used; - - public MemoryInfo(){ - } - - /** - * Fill object fwith info. - * @param runtime used to get memory info from. - * @return itself for chaining - */ - public MemoryInfo init(Runtime runtime){ - total = runtime.maxMemory(); - used = runtime.totalMemory() - runtime.freeMemory(); - return this; - } - - public long getTotal(){ - return total; - } - - public String getTotalFormated(){ - return formatMemory(getTotal()); - } - - public long getFree(){ - return getTotal() - getUsed(); - } - public String getFreeFormated(){ - return formatMemory(getFree()); - } - - public long getUsed(){ - return used; - } - - public String getUsedFormated(){ - return formatMemory(getUsed()); - } - - public long getFreePercentage(){ - return getFree() * 100 / getTotal(); - } - - private String formatMemory(long bytes){ - if(bytes > 1024L*1024L){ - return bytes/(1024L *1024L) + " MB"; - } else if(bytes > 1024L){ - return bytes/(1024L) + " kB"; - } else { - return bytes + " B"; - } - } - - } - - public static class SystemInfo implements Serializable { - - protected String javaVersion; - protected String javaVendor; - protected String javaVm; - protected String javaVmVersion; - protected String javaRuntime; - protected String javaHome; - protected String osName; - protected String osArchitecture; - protected String osVersion; - protected String fileEncoding; - protected String userName; - protected String userDir; - protected String userTimezone; - protected String userLocale; - - public SystemInfo() { - } - - /** - * Fill object with info about current system loaded from {@link System} properties. - * @return object itself for chaining - */ - protected SystemInfo init(){ - javaVersion = System.getProperty("java.version"); - javaVendor = System.getProperty("java.vendor"); - javaVm = System.getProperty("java.vm.name"); - javaVmVersion = System.getProperty("java.vm.version"); - javaRuntime = System.getProperty("java.runtime.name"); - javaHome = System.getProperty("java.home"); - osName = System.getProperty("os.name"); - osArchitecture = System.getProperty("os.arch"); - osVersion = System.getProperty("os.version"); - fileEncoding = System.getProperty("file.encoding"); - userName = System.getProperty("user.name"); - userDir = System.getProperty("user.dir"); - userTimezone = System.getProperty("user.timezone"); - userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); - return this; - } - - public String getJavaVersion(){ - return javaVersion; - } - - public String getJavaVendor(){ - return javaVendor; - } - - public String getJavaVm(){ - return javaVm; - } - - public String getJavaVmVersion(){ - return javaVmVersion; - } - - public String getJavaRuntime(){ - return javaRuntime; - } - - public String getJavaHome(){ - return javaHome; - } - - public String getOsName(){ - return osName; - } - - public String getOsArchitecture(){ - return osArchitecture; - } - - public String getOsVersion(){ - return osVersion; - } - - public String getFileEncoding(){ - return fileEncoding; - } - - public String getUserName(){ - return userName; - } - - public String getUserDir(){ - return userDir; - } - - public String getUserTimezone(){ - return userTimezone; - } - - public String getUserLocale(){ - return userLocale; - } - } - - public static class ServerInfoRepresentation implements Serializable { + public static class ServerInfoRepresentation { private String version; + private String serverTime; - private long serverStartupTime; private Map> themes; @@ -393,76 +208,13 @@ public class ServerInfoAdminResource { private Map> builtinProtocolMappers; private Map> enums; - - private MemoryInfo memoryInfo; - private SystemInfo systemInfo; - - private ProviderOperationalInfo jpaInfo; - private ProviderOperationalInfo mongoDbInfo; public ServerInfoRepresentation() { } - - public SystemInfo getSystemInfo(){ - return systemInfo; - } - - public MemoryInfo getMemoryInfo(){ - return memoryInfo; - } - - public ProviderOperationalInfo getJpaInfo() { - return jpaInfo; - } - - public ProviderOperationalInfo getMongoDbInfo() { - return mongoDbInfo; - } public String getServerTime() { return serverTime; } - - public long getServerStartupTime() { - return serverStartupTime; - } - - /** - * @return server startup time formatted - */ - public String getServerStartupTimeFormatted() { - return (new Date(serverStartupTime)).toString(); - } - - /** - * @return server uptime in millis - */ - public long getServerUptimeMillis(){ - return System.currentTimeMillis() - serverStartupTime; - } - - /** - * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" - */ - public String getServerUptime(){ - long diffInSeconds = getServerUptimeMillis()/1000; - long diff[] = new long[] { 0, 0, 0, 0 }; - /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); - /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; - /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; - /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); - - return String.format( - "%d day%s, %d hour%s, %d minute%s, %d second%s", - diff[0], - diff[0] != 1 ? "s" : "", - diff[1], - diff[1] != 1 ? "s" : "", - diff[2], - diff[2] != 1 ? "s" : "", - diff[3], - diff[3] != 1 ? "s" : ""); - } public String getVersion() { return version; @@ -517,7 +269,7 @@ public class ServerInfoAdminResource { } } - public static class SpiInfoRepresentation implements Serializable { + public static class SpiInfoRepresentation { private String name; private boolean internal; private Set implementations; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java new file mode 100644 index 00000000000..c6a720816cf --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java @@ -0,0 +1,375 @@ +package org.keycloak.services.resources.admin; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashSet; +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.models.KeycloakSession; +import org.keycloak.provider.ServerInfoAwareProviderFactory; +import org.keycloak.provider.Spi; + +/** + * REST endpoint which return info for "Server Info" page. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public class ServerInfoPageAdminResource { + + private static final Logger logger = Logger.getLogger(ServerInfoPageAdminResource.class); + + @Context + private KeycloakSession session; + + /** + * Returns a list of providers and other operational info about the page. + * + * @return + */ + @GET + public ServerInfoRepresentation getInfo() { + ServerInfoRepresentation info = new ServerInfoRepresentation(); + info.version = Version.VERSION; + info.serverTime = new Date().toString(); + info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); + info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); + info.systemInfo = (new SystemInfo()).init(); + setProviders(info); + return info; + } + + private void setProviders(ServerInfoRepresentation info) { + List providers = new LinkedList<>(); + for (Spi spi : ServiceLoader.load(Spi.class)) { + SpiInfoRepresentation spiRep = new SpiInfoRepresentation(); + spiRep.setName(spi.getName()); + spiRep.setInternal(spi.isInternal()); + spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass())); + Set s = session.listProviderIds(spi.getProviderClass()); + Set srs = new HashSet<>(); + + if(s!=null){ + for(String name: s){ + SpiImplementationRepresentation sr = new SpiImplementationRepresentation(name); + if(spiRep.isSystemInfo()){ + sr.setOperationalInfo(((ServerInfoAwareProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name)).getOperationalInfo()); + } + srs.add(sr); + } + } + spiRep.setImplementations(srs); + providers.add(spiRep); + } + info.providers = providers; + } + + + public static class MemoryInfo implements Serializable { + + protected long total; + protected long used; + + public MemoryInfo(){ + } + + /** + * Fill object fwith info. + * @param runtime used to get memory info from. + * @return itself for chaining + */ + public MemoryInfo init(Runtime runtime){ + total = runtime.maxMemory(); + used = runtime.totalMemory() - runtime.freeMemory(); + return this; + } + + public long getTotal(){ + return total; + } + + public String getTotalFormated(){ + return formatMemory(getTotal()); + } + + public long getFree(){ + return getTotal() - getUsed(); + } + + public String getFreeFormated(){ + return formatMemory(getFree()); + } + + public long getUsed(){ + return used; + } + + public String getUsedFormated(){ + return formatMemory(getUsed()); + } + + public long getFreePercentage(){ + return getFree() * 100 / getTotal(); + } + + private String formatMemory(long bytes){ + if(bytes > 1024L*1024L){ + return bytes/(1024L *1024L) + " MB"; + } else if(bytes > 1024L){ + return bytes/(1024L) + " kB"; + } else { + return bytes + " B"; + } + } + + } + + public static class SystemInfo implements Serializable { + + protected String javaVersion; + protected String javaVendor; + protected String javaVm; + protected String javaVmVersion; + protected String javaRuntime; + protected String javaHome; + protected String osName; + protected String osArchitecture; + protected String osVersion; + protected String fileEncoding; + protected String userName; + protected String userDir; + protected String userTimezone; + protected String userLocale; + + public SystemInfo() { + } + + /** + * Fill object with info about current system loaded from {@link System} properties. + * @return object itself for chaining + */ + protected SystemInfo init(){ + javaVersion = System.getProperty("java.version"); + javaVendor = System.getProperty("java.vendor"); + javaVm = System.getProperty("java.vm.name"); + javaVmVersion = System.getProperty("java.vm.version"); + javaRuntime = System.getProperty("java.runtime.name"); + javaHome = System.getProperty("java.home"); + osName = System.getProperty("os.name"); + osArchitecture = System.getProperty("os.arch"); + osVersion = System.getProperty("os.version"); + fileEncoding = System.getProperty("file.encoding"); + userName = System.getProperty("user.name"); + userDir = System.getProperty("user.dir"); + userTimezone = System.getProperty("user.timezone"); + userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); + return this; + } + + public String getJavaVersion(){ + return javaVersion; + } + + public String getJavaVendor(){ + return javaVendor; + } + + public String getJavaVm(){ + return javaVm; + } + + public String getJavaVmVersion(){ + return javaVmVersion; + } + + public String getJavaRuntime(){ + return javaRuntime; + } + + public String getJavaHome(){ + return javaHome; + } + + public String getOsName(){ + return osName; + } + + public String getOsArchitecture(){ + return osArchitecture; + } + + public String getOsVersion(){ + return osVersion; + } + + public String getFileEncoding(){ + return fileEncoding; + } + + public String getUserName(){ + return userName; + } + + public String getUserDir(){ + return userDir; + } + + public String getUserTimezone(){ + return userTimezone; + } + + public String getUserLocale(){ + return userLocale; + } + } + + public static class ServerInfoRepresentation implements Serializable { + + private String version; + private String serverTime; + private long serverStartupTime; + + + private List providers; + + private MemoryInfo memoryInfo; + private SystemInfo systemInfo; + + public ServerInfoRepresentation() { + } + + public SystemInfo getSystemInfo(){ + return systemInfo; + } + + public MemoryInfo getMemoryInfo(){ + return memoryInfo; + } + + public String getServerTime() { + return serverTime; + } + + public long getServerStartupTime() { + return serverStartupTime; + } + + /** + * @return server startup time formatted + */ + public String getServerStartupTimeFormatted() { + return (new Date(serverStartupTime)).toString(); + } + + /** + * @return server uptime in millis + */ + public long getServerUptimeMillis(){ + return System.currentTimeMillis() - serverStartupTime; + } + + /** + * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" + */ + public String getServerUptime(){ + long diffInSeconds = getServerUptimeMillis()/1000; + long diff[] = new long[] { 0, 0, 0, 0 }; + /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); + /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; + /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; + /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); + + return String.format( + "%d day%s, %d hour%s, %d minute%s, %d second%s", + diff[0], + diff[0] != 1 ? "s" : "", + diff[1], + diff[1] != 1 ? "s" : "", + diff[2], + diff[2] != 1 ? "s" : "", + diff[3], + diff[3] != 1 ? "s" : ""); + } + + public String getVersion() { + return version; + } + + + public List getProviders() { + return providers; + } + } + + public static class SpiInfoRepresentation implements Serializable { + private String name; + private boolean internal; + private boolean systemInfo; + private Set implementations; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isInternal() { + return internal; + } + + public void setInternal(boolean internal) { + this.internal = internal; + } + + public Set getImplementations() { + return implementations; + } + + public boolean isSystemInfo() { + return systemInfo; + } + + public void setSystemInfo(boolean systemInfo) { + this.systemInfo = systemInfo; + } + + public void setImplementations(Set implementations) { + this.implementations = implementations; + } + } + + public static class SpiImplementationRepresentation implements Serializable { + + private String name; + private Map operationalInfo; + + public SpiImplementationRepresentation(String name) { + super(); + this.name = name; + } + + public Map getOperationalInfo() { + return operationalInfo; + } + + public void setOperationalInfo(Map operationalInfo) { + this.operationalInfo = operationalInfo; + } + + public String getName() { + return name; + } + + } +} 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 2cca19a0c98..33ead317e41 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 @@ -317,13 +317,41 @@ public class AdminAPITest { Assert.assertNotNull(response); Assert.assertEquals(Version.VERSION, response.get("version")); Assert.assertNotNull(response.get("serverTime")); + Assert.assertNotNull(response.get("providers")); + Assert.assertNotNull(response.get("themes")); + Assert.assertNotNull(response.get("enums")); + + // System.out.println(response); + + } + + @Test + public void testServerInfoPage() { + + String token = createToken(); + final String authHeader = "Bearer " + token; + ClientRequestFilter authFilter = new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); + } + }; + Client client = ClientBuilder.newBuilder().register(authFilter).build(); + UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); + WebTarget target = client.target(AdminRoot.adminBaseUrl(authBase).path("serverinfopage")); + + Map response = target.request().accept("application/json").get(Map.class); + + Assert.assertNotNull(response); + Assert.assertEquals(Version.VERSION, response.get("version")); + Assert.assertNotNull(response.get("serverTime")); + Assert.assertNotNull(response.get("providers")); Assert.assertNotNull(response.get("serverStartupTime")); Assert.assertNotNull(response.get("memoryInfo")); - Assert.assertNotNull(response.get("jpaInfo")); - Assert.assertNull(response.get("mongoDbInfo")); + Assert.assertNotNull(response.get("systemInfo")); - System.out.println(response); + // System.out.println(response); } From 244d3452d0a60acfb7c4cc2cca6187729a4bd62e Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Fri, 24 Jul 2015 11:07:01 +0200 Subject: [PATCH 11/14] KEYCLOAK-1542 - removed unused code from the page template --- .../base/admin/resources/partials/server-info.html | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index 0dfac4cb9ac..991f2084010 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -96,19 +96,6 @@
- -
- Database Info -
- - - - - -
{{key}}{{value}}
-
-
-
Providers From d1964c20abbf93731781e230747b0155224c597d Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Fri, 24 Jul 2015 14:47:37 +0200 Subject: [PATCH 12/14] Refactored server-info and updated admin console --- .../theme/base/admin/resources/js/app.js | 19 +- .../admin/resources/js/controllers/clients.js | 2 +- .../admin/resources/js/controllers/realm.js | 32 +- .../theme/base/admin/resources/js/loaders.js | 10 +- .../theme/base/admin/resources/js/services.js | 24 +- .../partials/server-info-providers.html | 55 +++ .../admin/resources/partials/server-info.html | 264 +++++------- .../services/resources/admin/AdminRoot.java | 27 +- .../admin/ServerInfoPageAdminResource.java | 375 ------------------ .../admin/info/MemoryInfoRepresentation.java | 54 +++ .../admin/info/ProviderRepresentation.java | 17 + .../{ => info}/ServerInfoAdminResource.java | 200 ++-------- .../admin/info/ServerInfoRepresentation.java | 108 +++++ .../admin/info/SpiInfoRepresentation.java | 39 ++ .../admin/info/SystemInfoRepresentation.java | 217 ++++++++++ 15 files changed, 681 insertions(+), 762 deletions(-) create mode 100755 forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html delete mode 100644 services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/info/MemoryInfoRepresentation.java create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/info/ProviderRepresentation.java rename services/src/main/java/org/keycloak/services/resources/admin/{ => info}/ServerInfoAdminResource.java (54%) create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoRepresentation.java create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/info/SpiInfoRepresentation.java create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/info/SystemInfoRepresentation.java diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js index 4f02ce6b486..5e015981998 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js @@ -82,8 +82,8 @@ module.config([ '$routeProvider', function($routeProvider) { realm : function(RealmLoader) { return RealmLoader(); }, - serverInfo : function(ServerInfoLoader) { - return ServerInfoLoader(); + serverInfo : function(ServerInfo) { + return ServerInfo.delay; } }, controller : 'RealmLoginSettingsCtrl' @@ -1135,11 +1135,20 @@ module.config([ '$routeProvider', function($routeProvider) { .when('/server-info', { templateUrl : resourceUrl + '/partials/server-info.html', resolve : { - serverInfoPage : function(ServerInfoPageLoader) { - return ServerInfoPageLoader(); + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); } }, - controller : 'ServerInfoPageCtrl' + controller : 'ServerInfoCtrl' + }) + .when('/server-info/providers', { + templateUrl : resourceUrl + '/partials/server-info-providers.html', + resolve : { + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ServerInfoCtrl' }) .when('/logout', { templateUrl : resourceUrl + '/partials/home.html', diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js index 6331c9d39a5..8ad8ae646ed 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js @@ -549,7 +549,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se "bearer-only" ]; - $scope.protocols = serverInfo.protocols; + $scope.protocols = Object.keys(serverInfo.providers['login-protocol'].providers); $scope.signatureAlgorithms = [ "RSA_SHA1", diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js index 0b5745a0810..15a8fa9223a 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js @@ -7,9 +7,6 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, WhoAmI, Current, $ $scope.resourceUrl = resourceUrl; $scope.auth = Auth; $scope.serverInfo = ServerInfo.get(); - $scope.serverInfoUpdate = function() { - $scope.serverInfo = ServerInfo.get(); - }; function hasAnyAccess() { var realmAccess = Auth.user && Auth.user['realm_access']; @@ -125,18 +122,23 @@ module.controller('RealmTabCtrl', function(Dialog, $scope, Current, Realm, Notif }; }); -module.controller('ServerInfoPageCtrl', function($scope, ServerInfoPage) { - $scope.serverInfoPage = ServerInfoPage.get(); - $scope.serverInfoPageUpdate = function() { - $scope.serverInfoPage = ServerInfoPage.get(); - }; -}); +module.controller('ServerInfoCtrl', function($scope, ServerInfo) { + ServerInfo.reload(); -module.controller('ServerInfoPageCtrl', function($scope, ServerInfoPage) { - $scope.serverInfoPage = ServerInfoPage.get(); - $scope.serverInfoPageUpdate = function() { - $scope.serverInfoPage = ServerInfoPage.get(); - }; + $scope.serverInfo = ServerInfo.get(); + + $scope.$watch($scope.serverInfo, function() { + $scope.providers = []; + for(var spi in $scope.serverInfo.providers) { + var p = angular.copy($scope.serverInfo.providers[spi]); + p.name = spi; + $scope.providers.push(p) + } + }); + + $scope.serverInfoReload = function() { + ServerInfo.reload(); + } }); module.controller('RealmListCtrl', function($scope, Realm, Current) { @@ -1231,7 +1233,7 @@ module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmE } }); - $scope.eventListeners = serverInfo.eventListeners; + $scope.eventListeners = Object.keys(serverInfo.providers.eventsListener.providers); $scope.eventSelectOptions = { 'multiple': true, diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js index 2e65b3c7124..c3477594136 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js @@ -35,12 +35,10 @@ module.factory('RealmListLoader', function(Loader, Realm, $q) { return Loader.get(Realm); }); -module.factory('ServerInfoLoader', function(Loader, ServerInfo, $q) { - return Loader.get(ServerInfo); -}); - -module.factory('ServerInfoPageLoader', function(Loader, ServerInfoPage, $q) { - return Loader.get(ServerInfoPage); +module.factory('ServerInfoLoader', function(Loader, ServerInfo) { + return function() { + return ServerInfo.promise; + }; }); module.factory('RealmLoader', function(Loader, Realm, $route, $q) { diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js index b5d8c330f3d..04929ef7f16 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js @@ -215,12 +215,26 @@ module.factory('RealmLDAPConnectionTester', function($resource) { return $resource(authUrl + '/admin/realms/:realm/testLDAPConnection'); }); -module.factory('ServerInfo', function($resource) { - return $resource(authUrl + '/admin/serverinfo'); -}); +module.service('ServerInfo', function($resource, $q, $http) { + var info = {}; + var delay = $q.defer(); -module.factory('ServerInfoPage', function($resource) { - return $resource(authUrl + '/admin/serverinfopage'); + $http.get(authUrl + '/admin/serverinfo').success(function(data) { + info = data; + delay.resolve(info); + }); + + return { + get: function() { + return info; + }, + reload: function() { + $http.get(authUrl + '/admin/serverinfo').success(function(data) { + angular.copy(data, info); + }); + }, + promise: delay.promise + } }); diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html new file mode 100755 index 00000000000..6f8bbb49d7a --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html @@ -0,0 +1,55 @@ +
+

+ Server Info + +

+ + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
SPIProviders
{{spi.name}} +
+ {{providerName}} + + + + + + + +
{{key}}{{value}}
+
+
+
+
+ + \ No newline at end of file diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html index 991f2084010..a92c774b259 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html @@ -1,174 +1,104 @@ -
-

Server Info

+
+

+ Server Info + +

- - - - - - - - - - - - - -
Keycloak Version{{serverInfoPage.version}}
Server Time{{serverInfoPage.serverTime}} (update)
Server Uptime{{serverInfoPage.serverUptime}}
+ + + + + + + + + + + + + + + +
Keycloak Version{{serverInfo.systemInfo.version}}
Server Time{{serverInfo.systemInfo.serverTime}}
Server Uptime{{serverInfo.systemInfo.uptime}}
-
- Java VM Memory Statistics -
- - - - - - - - - - - - - -
Total Memory{{serverInfoPage.memoryInfo.totalFormated}}
Free Memory{{serverInfoPage.memoryInfo.freeFormated}} ({{serverInfoPage.memoryInfo.freePercentage}}%)
Used Memory{{serverInfoPage.memoryInfo.usedFormated}}
-
-
-
- System Info -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Memory +
Current Working Directory{{serverInfoPage.systemInfo.userDir}}
Java Version{{serverInfoPage.systemInfo.javaVersion}}
Java Vendor{{serverInfoPage.systemInfo.javaVendor}}
Java Runtime{{serverInfoPage.systemInfo.javaRuntime}}
Java VM{{serverInfoPage.systemInfo.javaVm}}
Java VM Version{{serverInfoPage.systemInfo.javaVmVersion}}
Java Home{{serverInfoPage.systemInfo.javaHome}}
User Name{{serverInfoPage.systemInfo.userName}}
User Timezone{{serverInfoPage.systemInfo.userTimezone}}
User Locale{{serverInfoPage.systemInfo.userLocale}}
System Encoding{{serverInfoPage.systemInfo.fileEncoding}}
Operating System{{serverInfoPage.systemInfo.osName}} {{serverInfoPage.systemInfo.osVersion}}
OS Architecture{{serverInfoPage.systemInfo.osArchitecture}}
+ + + + + + + + + + + +
Total Memory{{serverInfo.memoryInfo.totalFormated}}
Free Memory{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
Used Memory{{serverInfo.memoryInfo.usedFormated}}
-
-
+
- Providers - -
-

Public SPIs

- For public SPIs there are built-in providers, but it's also supported to write your own custom providers. - - - - - - - - - - - - - - -
SPIProviders
{{spi.name}} -
- {{provider.name}} - - - - - - - -
{{key}}{{value}}
-
-
-
-
- -
-

Internal SPIs

- For internal SPIs there are only built-in providers. It's not recommended to write your own custom providers as internal SPIs may change or be removed without notice. - - - - - - - - - - - - - - -
SPIProviders
{{spi.name}} -
- {{provider.name}} - - - - - - - -
{{key}}{{value}}
-
-
-
-
+ System + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current Working Directory{{serverInfo.systemInfo.userDir}}
Java Version{{serverInfo.systemInfo.javaVersion}}
Java Vendor{{serverInfo.systemInfo.javaVendor}}
Java Runtime{{serverInfo.systemInfo.javaRuntime}}
Java VM{{serverInfo.systemInfo.javaVm}}
Java VM Version{{serverInfo.systemInfo.javaVmVersion}}
Java Home{{serverInfo.systemInfo.javaHome}}
User Name{{serverInfo.systemInfo.userName}}
User Timezone{{serverInfo.systemInfo.userTimezone}}
User Locale{{serverInfo.systemInfo.userLocale}}
System Encoding{{serverInfo.systemInfo.fileEncoding}}
Operating System{{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}}
OS Architecture{{serverInfo.systemInfo.osArchitecture}}
- \ No newline at end of file + + + \ No newline at end of file diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java index 6b3ca3eafa7..97c147247ce 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java @@ -20,6 +20,7 @@ import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.resources.Cors; +import org.keycloak.services.resources.admin.info.ServerInfoAdminResource; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -218,32 +219,6 @@ public class AdminRoot { return adminResource; } - /** - * Operational information about the server for "Server Info" page - * - * @param headers - * @return - */ - @Path("serverinfopage") - public ServerInfoPageAdminResource getServerInfoPage(@Context final HttpHeaders headers) { - handlePreflightRequest(); - - AdminAuth auth = authenticateRealmAdminRequest(headers); - if (!isAdmin(auth)) { - throw new ForbiddenException(); - } - - if (auth != null) { - logger.debug("authenticated admin access for: " + auth.getUser().getUsername()); - } - - Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response); - - ServerInfoPageAdminResource adminResource = new ServerInfoPageAdminResource(); - ResteasyProviderFactory.getInstance().injectProperties(adminResource); - return adminResource; - } - protected boolean isAdmin(AdminAuth auth) { RealmManager realmManager = new RealmManager(session); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java deleted file mode 100644 index c6a720816cf..00000000000 --- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java +++ /dev/null @@ -1,375 +0,0 @@ -package org.keycloak.services.resources.admin; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashSet; -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.models.KeycloakSession; -import org.keycloak.provider.ServerInfoAwareProviderFactory; -import org.keycloak.provider.Spi; - -/** - * REST endpoint which return info for "Server Info" page. - * - * @author Vlastimil Elias (velias at redhat dot com) - */ -public class ServerInfoPageAdminResource { - - private static final Logger logger = Logger.getLogger(ServerInfoPageAdminResource.class); - - @Context - private KeycloakSession session; - - /** - * Returns a list of providers and other operational info about the page. - * - * @return - */ - @GET - public ServerInfoRepresentation getInfo() { - ServerInfoRepresentation info = new ServerInfoRepresentation(); - info.version = Version.VERSION; - info.serverTime = new Date().toString(); - info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp(); - info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime()); - info.systemInfo = (new SystemInfo()).init(); - setProviders(info); - return info; - } - - private void setProviders(ServerInfoRepresentation info) { - List providers = new LinkedList<>(); - for (Spi spi : ServiceLoader.load(Spi.class)) { - SpiInfoRepresentation spiRep = new SpiInfoRepresentation(); - spiRep.setName(spi.getName()); - spiRep.setInternal(spi.isInternal()); - spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass())); - Set s = session.listProviderIds(spi.getProviderClass()); - Set srs = new HashSet<>(); - - if(s!=null){ - for(String name: s){ - SpiImplementationRepresentation sr = new SpiImplementationRepresentation(name); - if(spiRep.isSystemInfo()){ - sr.setOperationalInfo(((ServerInfoAwareProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name)).getOperationalInfo()); - } - srs.add(sr); - } - } - spiRep.setImplementations(srs); - providers.add(spiRep); - } - info.providers = providers; - } - - - public static class MemoryInfo implements Serializable { - - protected long total; - protected long used; - - public MemoryInfo(){ - } - - /** - * Fill object fwith info. - * @param runtime used to get memory info from. - * @return itself for chaining - */ - public MemoryInfo init(Runtime runtime){ - total = runtime.maxMemory(); - used = runtime.totalMemory() - runtime.freeMemory(); - return this; - } - - public long getTotal(){ - return total; - } - - public String getTotalFormated(){ - return formatMemory(getTotal()); - } - - public long getFree(){ - return getTotal() - getUsed(); - } - - public String getFreeFormated(){ - return formatMemory(getFree()); - } - - public long getUsed(){ - return used; - } - - public String getUsedFormated(){ - return formatMemory(getUsed()); - } - - public long getFreePercentage(){ - return getFree() * 100 / getTotal(); - } - - private String formatMemory(long bytes){ - if(bytes > 1024L*1024L){ - return bytes/(1024L *1024L) + " MB"; - } else if(bytes > 1024L){ - return bytes/(1024L) + " kB"; - } else { - return bytes + " B"; - } - } - - } - - public static class SystemInfo implements Serializable { - - protected String javaVersion; - protected String javaVendor; - protected String javaVm; - protected String javaVmVersion; - protected String javaRuntime; - protected String javaHome; - protected String osName; - protected String osArchitecture; - protected String osVersion; - protected String fileEncoding; - protected String userName; - protected String userDir; - protected String userTimezone; - protected String userLocale; - - public SystemInfo() { - } - - /** - * Fill object with info about current system loaded from {@link System} properties. - * @return object itself for chaining - */ - protected SystemInfo init(){ - javaVersion = System.getProperty("java.version"); - javaVendor = System.getProperty("java.vendor"); - javaVm = System.getProperty("java.vm.name"); - javaVmVersion = System.getProperty("java.vm.version"); - javaRuntime = System.getProperty("java.runtime.name"); - javaHome = System.getProperty("java.home"); - osName = System.getProperty("os.name"); - osArchitecture = System.getProperty("os.arch"); - osVersion = System.getProperty("os.version"); - fileEncoding = System.getProperty("file.encoding"); - userName = System.getProperty("user.name"); - userDir = System.getProperty("user.dir"); - userTimezone = System.getProperty("user.timezone"); - userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString()); - return this; - } - - public String getJavaVersion(){ - return javaVersion; - } - - public String getJavaVendor(){ - return javaVendor; - } - - public String getJavaVm(){ - return javaVm; - } - - public String getJavaVmVersion(){ - return javaVmVersion; - } - - public String getJavaRuntime(){ - return javaRuntime; - } - - public String getJavaHome(){ - return javaHome; - } - - public String getOsName(){ - return osName; - } - - public String getOsArchitecture(){ - return osArchitecture; - } - - public String getOsVersion(){ - return osVersion; - } - - public String getFileEncoding(){ - return fileEncoding; - } - - public String getUserName(){ - return userName; - } - - public String getUserDir(){ - return userDir; - } - - public String getUserTimezone(){ - return userTimezone; - } - - public String getUserLocale(){ - return userLocale; - } - } - - public static class ServerInfoRepresentation implements Serializable { - - private String version; - private String serverTime; - private long serverStartupTime; - - - private List providers; - - private MemoryInfo memoryInfo; - private SystemInfo systemInfo; - - public ServerInfoRepresentation() { - } - - public SystemInfo getSystemInfo(){ - return systemInfo; - } - - public MemoryInfo getMemoryInfo(){ - return memoryInfo; - } - - public String getServerTime() { - return serverTime; - } - - public long getServerStartupTime() { - return serverStartupTime; - } - - /** - * @return server startup time formatted - */ - public String getServerStartupTimeFormatted() { - return (new Date(serverStartupTime)).toString(); - } - - /** - * @return server uptime in millis - */ - public long getServerUptimeMillis(){ - return System.currentTimeMillis() - serverStartupTime; - } - - /** - * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds" - */ - public String getServerUptime(){ - long diffInSeconds = getServerUptimeMillis()/1000; - long diff[] = new long[] { 0, 0, 0, 0 }; - /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); - /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; - /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; - /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); - - return String.format( - "%d day%s, %d hour%s, %d minute%s, %d second%s", - diff[0], - diff[0] != 1 ? "s" : "", - diff[1], - diff[1] != 1 ? "s" : "", - diff[2], - diff[2] != 1 ? "s" : "", - diff[3], - diff[3] != 1 ? "s" : ""); - } - - public String getVersion() { - return version; - } - - - public List getProviders() { - return providers; - } - } - - public static class SpiInfoRepresentation implements Serializable { - private String name; - private boolean internal; - private boolean systemInfo; - private Set implementations; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isInternal() { - return internal; - } - - public void setInternal(boolean internal) { - this.internal = internal; - } - - public Set getImplementations() { - return implementations; - } - - public boolean isSystemInfo() { - return systemInfo; - } - - public void setSystemInfo(boolean systemInfo) { - this.systemInfo = systemInfo; - } - - public void setImplementations(Set implementations) { - this.implementations = implementations; - } - } - - public static class SpiImplementationRepresentation implements Serializable { - - private String name; - private Map operationalInfo; - - public SpiImplementationRepresentation(String name) { - super(); - this.name = name; - } - - public Map getOperationalInfo() { - return operationalInfo; - } - - public void setOperationalInfo(Map operationalInfo) { - this.operationalInfo = operationalInfo; - } - - public String getName() { - return name; - } - - } -} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/MemoryInfoRepresentation.java b/services/src/main/java/org/keycloak/services/resources/admin/info/MemoryInfoRepresentation.java new file mode 100644 index 00000000000..56a1110d720 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/MemoryInfoRepresentation.java @@ -0,0 +1,54 @@ +package org.keycloak.services.resources.admin.info; + +public class MemoryInfoRepresentation { + + protected long total; + protected long used; + + public static MemoryInfoRepresentation create() { + MemoryInfoRepresentation rep = new MemoryInfoRepresentation(); + Runtime runtime = Runtime.getRuntime(); + rep.total = runtime.maxMemory(); + rep.used = runtime.totalMemory() - runtime.freeMemory(); + return rep; + } + + public long getTotal() { + return total; + } + + public String getTotalFormated() { + return formatMemory(getTotal()); + } + + public long getFree() { + return getTotal() - getUsed(); + } + + public String getFreeFormated() { + return formatMemory(getFree()); + } + + public long getUsed() { + return used; + } + + public String getUsedFormated() { + return formatMemory(getUsed()); + } + + public long getFreePercentage() { + return getFree() * 100 / getTotal(); + } + + private String formatMemory(long bytes) { + if (bytes > 1024L * 1024L) { + return bytes / (1024L * 1024L) + " MB"; + } else if (bytes > 1024L) { + return bytes / (1024L) + " kB"; + } else { + return bytes + " B"; + } + } + +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ProviderRepresentation.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ProviderRepresentation.java new file mode 100644 index 00000000000..ffcaeb16512 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ProviderRepresentation.java @@ -0,0 +1,17 @@ +package org.keycloak.services.resources.admin.info; + +import java.util.Map; + +public class ProviderRepresentation { + + private Map operationalInfo; + + public Map getOperationalInfo() { + return operationalInfo; + } + + public void setOperationalInfo(Map operationalInfo) { + this.operationalInfo = operationalInfo; + } + +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java similarity index 54% rename from services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java rename to services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java index 4f1c22575b0..8223556b188 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java @@ -1,9 +1,7 @@ -package org.keycloak.services.resources.admin; +package org.keycloak.services.resources.admin.info; -import org.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; -import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventType; import org.keycloak.events.admin.OperationType; import org.keycloak.exportimport.ClientImporter; @@ -18,6 +16,7 @@ import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.ProtocolMapper; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.ServerInfoAwareProviderFactory; import org.keycloak.provider.Spi; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -26,14 +25,7 @@ import org.keycloak.social.SocialIdentityProvider; import javax.ws.rs.GET; import javax.ws.rs.core.Context; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; +import java.util.*; /** * @author Stian Thorgersen @@ -53,13 +45,12 @@ public class ServerInfoAdminResource { @GET public ServerInfoRepresentation getInfo() { ServerInfoRepresentation info = new ServerInfoRepresentation(); - info.version = Version.VERSION; - info.serverTime = new Date().toString(); + info.setSystemInfo(SystemInfoRepresentation.create(session)); + info.setMemoryInfo(MemoryInfoRepresentation.create()); + setSocialProviders(info); setIdentityProviders(info); setThemes(info); - setEventListeners(info); - setProtocols(info); setClientImporters(info); setProviders(info); setProtocolMapperTypes(info); @@ -69,42 +60,55 @@ public class ServerInfoAdminResource { } private void setProviders(ServerInfoRepresentation info) { - List providers = new LinkedList<>(); + Map spis = new HashMap<>(); for (Spi spi : ServiceLoader.load(Spi.class)) { SpiInfoRepresentation spiRep = new SpiInfoRepresentation(); - spiRep.setName(spi.getName()); spiRep.setInternal(spi.isInternal()); - spiRep.setImplementations(session.listProviderIds(spi.getProviderClass())); - providers.add(spiRep); + spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass())); + Set providerIds = session.listProviderIds(spi.getProviderClass()); + Map providers = new HashMap<>(); + + if (providerIds != null) { + for (String name : providerIds) { + ProviderRepresentation provider = new ProviderRepresentation(); + if (spiRep.isSystemInfo()) { + provider.setOperationalInfo(((ServerInfoAwareProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name)).getOperationalInfo()); + } + providers.put(name, provider); + } + } + spiRep.setProviders(providers); + + spis.put(spi.getName(), spiRep); } - info.providers = providers; + info.setProviders(spis); } private void setThemes(ServerInfoRepresentation info) { ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending"); - info.themes = new HashMap>(); + info.setThemes(new HashMap>()); for (Theme.Type type : Theme.Type.values()) { List themes = new LinkedList(themeProvider.nameSet(type)); Collections.sort(themes); - info.themes.put(type.toString().toLowerCase(), themes); + info.getThemes().put(type.toString().toLowerCase(), themes); } } private void setSocialProviders(ServerInfoRepresentation info) { - info.socialProviders = new LinkedList<>(); + info.setSocialProviders(new LinkedList>()); List providerFactories = session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class); - setIdentityProviders(providerFactories, info.socialProviders, "Social"); + setIdentityProviders(providerFactories, info.getSocialProviders(), "Social"); } private void setIdentityProviders(ServerInfoRepresentation info) { - info.identityProviders = new LinkedList<>(); + info.setIdentityProviders(new LinkedList>()); List providerFactories = session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class); - setIdentityProviders(providerFactories, info.identityProviders, "User-defined"); + setIdentityProviders(providerFactories, info.getIdentityProviders(), "User-defined"); providerFactories = session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class); - setIdentityProviders(providerFactories, info.identityProviders, "Social"); + setIdentityProviders(providerFactories, info.getIdentityProviders(), "Social"); } public void setIdentityProviders(List factories, List> providers, String groupName) { @@ -119,31 +123,14 @@ public class ServerInfoAdminResource { } } - private void setEventListeners(ServerInfoRepresentation info) { - info.eventListeners = new LinkedList(); - - Set providers = session.listProviderIds(EventListenerProvider.class); - if (providers != null) { - info.eventListeners.addAll(providers); - } - } - - private void setProtocols(ServerInfoRepresentation info) { - info.protocols = new LinkedList(); - for (ProviderFactory p : session.getKeycloakSessionFactory().getProviderFactories(LoginProtocol.class)) { - info.protocols.add(p.getId()); - } - Collections.sort(info.protocols); - } - private void setProtocolMapperTypes(ServerInfoRepresentation info) { - info.protocolMapperTypes = new HashMap>(); + info.setProtocolMapperTypes(new HashMap>()); for (ProviderFactory p : session.getKeycloakSessionFactory().getProviderFactories(ProtocolMapper.class)) { ProtocolMapper mapper = (ProtocolMapper)p; - List types = info.protocolMapperTypes.get(mapper.getProtocol()); + List types = info.getProtocolMapperTypes().get(mapper.getProtocol()); if (types == null) { types = new LinkedList(); - info.protocolMapperTypes.put(mapper.getProtocol(), types); + info.getProtocolMapperTypes().put(mapper.getProtocol(), types); } ProtocolMapperTypeRepresentation rep = new ProtocolMapperTypeRepresentation(); rep.setId(mapper.getId()); @@ -166,136 +153,25 @@ public class ServerInfoAdminResource { } private void setBuiltinProtocolMappers(ServerInfoRepresentation info) { - info.builtinProtocolMappers = new HashMap<>(); + info.setBuiltinProtocolMappers(new HashMap>()); for (ProviderFactory p : session.getKeycloakSessionFactory().getProviderFactories(LoginProtocol.class)) { LoginProtocolFactory factory = (LoginProtocolFactory)p; List mappers = new LinkedList<>(); for (ProtocolMapperModel mapper : factory.getBuiltinMappers()) { mappers.add(ModelToRepresentation.toRepresentation(mapper)); } - info.builtinProtocolMappers.put(p.getId(), mappers); + info.getBuiltinProtocolMappers().put(p.getId(), mappers); } } private void setClientImporters(ServerInfoRepresentation info) { - info.clientImporters = new LinkedList>(); + info.setClientImporters(new LinkedList>()); for (ProviderFactory p : session.getKeycloakSessionFactory().getProviderFactories(ClientImporter.class)) { ClientImporterFactory factory = (ClientImporterFactory)p; Map data = new HashMap(); data.put("id", factory.getId()); data.put("name", factory.getDisplayName()); - info.clientImporters.add(data); - } - } - - public static class ServerInfoRepresentation { - - private String version; - - private String serverTime; - - private Map> themes; - - private List> socialProviders; - public List> identityProviders; - private List protocols; - private List> clientImporters; - - private List providers; - - private List eventListeners; - private Map> protocolMapperTypes; - private Map> builtinProtocolMappers; - - private Map> enums; - - public ServerInfoRepresentation() { - } - - public String getServerTime() { - return serverTime; - } - - public String getVersion() { - return version; - } - - public Map> getThemes() { - return themes; - } - - public List> getSocialProviders() { - return socialProviders; - } - - public List> getIdentityProviders() { - return this.identityProviders; - } - - public List getEventListeners() { - return eventListeners; - } - - public List getProtocols() { - return protocols; - } - - public List> getClientImporters() { - return clientImporters; - } - - public List getProviders() { - return providers; - } - - public Map> getProtocolMapperTypes() { - return protocolMapperTypes; - } - - public Map> getBuiltinProtocolMappers() { - return builtinProtocolMappers; - } - - public void setBuiltinProtocolMappers(Map> builtinProtocolMappers) { - this.builtinProtocolMappers = builtinProtocolMappers; - } - - public Map> getEnums() { - return enums; - } - - public void setEnums(Map> enums) { - this.enums = enums; - } - } - - public static class SpiInfoRepresentation { - private String name; - private boolean internal; - private Set implementations; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isInternal() { - return internal; - } - - public void setInternal(boolean internal) { - this.internal = internal; - } - - public Set getImplementations() { - return implementations; - } - - public void setImplementations(Set implementations) { - this.implementations = implementations; + info.getClientImporters().add(data); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoRepresentation.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoRepresentation.java new file mode 100644 index 00000000000..9b7f4f5bbb8 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoRepresentation.java @@ -0,0 +1,108 @@ +package org.keycloak.services.resources.admin.info; + +import org.keycloak.representations.idm.ProtocolMapperRepresentation; +import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation; + +import java.util.List; +import java.util.Map; + +/** + * @author Stian Thorgersen + */ +public class ServerInfoRepresentation { + + private SystemInfoRepresentation systemInfo; + private MemoryInfoRepresentation memoryInfo; + + private Map> themes; + + private List> socialProviders; + private List> identityProviders; + private List> clientImporters; + + private Map providers; + + private Map> protocolMapperTypes; + private Map> builtinProtocolMappers; + + private Map> enums; + + public SystemInfoRepresentation getSystemInfo() { + return systemInfo; + } + + public void setSystemInfo(SystemInfoRepresentation systemInfo) { + this.systemInfo = systemInfo; + } + + public MemoryInfoRepresentation getMemoryInfo() { + return memoryInfo; + } + + public void setMemoryInfo(MemoryInfoRepresentation memoryInfo) { + this.memoryInfo = memoryInfo; + } + public Map> getThemes() { + return themes; + } + + public void setThemes(Map> themes) { + this.themes = themes; + } + + public List> getSocialProviders() { + return socialProviders; + } + + public void setSocialProviders(List> socialProviders) { + this.socialProviders = socialProviders; + } + + public List> getIdentityProviders() { + return identityProviders; + } + + public void setIdentityProviders(List> identityProviders) { + this.identityProviders = identityProviders; + } + + public List> getClientImporters() { + return clientImporters; + } + + public void setClientImporters(List> clientImporters) { + this.clientImporters = clientImporters; + } + + public Map getProviders() { + return providers; + } + + public void setProviders(Map providers) { + this.providers = providers; + } + + public Map> getProtocolMapperTypes() { + return protocolMapperTypes; + } + + public void setProtocolMapperTypes(Map> protocolMapperTypes) { + this.protocolMapperTypes = protocolMapperTypes; + } + + public Map> getBuiltinProtocolMappers() { + return builtinProtocolMappers; + } + + public void setBuiltinProtocolMappers(Map> builtinProtocolMappers) { + this.builtinProtocolMappers = builtinProtocolMappers; + } + + public Map> getEnums() { + return enums; + } + + public void setEnums(Map> enums) { + this.enums = enums; + } +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/SpiInfoRepresentation.java b/services/src/main/java/org/keycloak/services/resources/admin/info/SpiInfoRepresentation.java new file mode 100644 index 00000000000..3f94a5a9f33 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/SpiInfoRepresentation.java @@ -0,0 +1,39 @@ +package org.keycloak.services.resources.admin.info; + +import java.util.Map; + +/** + * @author Stian Thorgersen + */ +public class SpiInfoRepresentation { + + private boolean internal; + private boolean systemInfo; + + private Map providers; + + public boolean isInternal() { + return internal; + } + + public void setInternal(boolean internal) { + this.internal = internal; + } + + public boolean isSystemInfo() { + return systemInfo; + } + + public void setSystemInfo(boolean systemInfo) { + this.systemInfo = systemInfo; + } + + public Map getProviders() { + return providers; + } + + public void setProviders(Map providers) { + this.providers = providers; + } + +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/SystemInfoRepresentation.java b/services/src/main/java/org/keycloak/services/resources/admin/info/SystemInfoRepresentation.java new file mode 100644 index 00000000000..bc0329a785e --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/SystemInfoRepresentation.java @@ -0,0 +1,217 @@ +package org.keycloak.services.resources.admin.info; + +import org.keycloak.Version; +import org.keycloak.models.KeycloakSession; + +import java.util.Date; +import java.util.Locale; + +public class SystemInfoRepresentation { + + private String version; + private String serverTime; + private String uptime; + private long uptimeMillis; + private String javaVersion; + private String javaVendor; + private String javaVm; + private String javaVmVersion; + private String javaRuntime; + private String javaHome; + private String osName; + private String osArchitecture; + private String osVersion; + private String fileEncoding; + private String userName; + private String userDir; + private String userTimezone; + private String userLocale; + + public static SystemInfoRepresentation create(KeycloakSession session) { + SystemInfoRepresentation rep = new SystemInfoRepresentation(); + rep.version = Version.VERSION; + rep.serverTime = new Date().toString(); + rep.uptimeMillis = System.currentTimeMillis() - session.getKeycloakSessionFactory().getServerStartupTimestamp(); + rep.uptime = formatUptime(rep.uptimeMillis); + rep.javaVersion = System.getProperty("java.version"); + rep.javaVendor = System.getProperty("java.vendor"); + rep.javaVm = System.getProperty("java.vm.name"); + rep.javaVmVersion = System.getProperty("java.vm.version"); + rep.javaRuntime = System.getProperty("java.runtime.name"); + rep.javaHome = System.getProperty("java.home"); + rep.osName = System.getProperty("os.name"); + rep.osArchitecture = System.getProperty("os.arch"); + rep.osVersion = System.getProperty("os.version"); + rep.fileEncoding = System.getProperty("file.encoding"); + rep.userName = System.getProperty("user.name"); + rep.userDir = System.getProperty("user.dir"); + rep.userTimezone = System.getProperty("user.timezone"); + rep.userLocale = (new Locale(System.getProperty("user.country"), System.getProperty("user.language")).toString()); + return rep; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getServerTime() { + return serverTime; + } + + public void setServerTime(String serverTime) { + this.serverTime = serverTime; + } + + public String getUptime() { + return uptime; + } + + public void setUptime(String uptime) { + this.uptime = uptime; + } + + public long getUptimeMillis() { + return uptimeMillis; + } + + public void setUptimeMillis(long uptimeMillis) { + this.uptimeMillis = uptimeMillis; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + public String getJavaVendor() { + return javaVendor; + } + + public void setJavaVendor(String javaVendor) { + this.javaVendor = javaVendor; + } + + public String getJavaVm() { + return javaVm; + } + + public void setJavaVm(String javaVm) { + this.javaVm = javaVm; + } + + public String getJavaVmVersion() { + return javaVmVersion; + } + + public void setJavaVmVersion(String javaVmVersion) { + this.javaVmVersion = javaVmVersion; + } + + public String getJavaRuntime() { + return javaRuntime; + } + + public void setJavaRuntime(String javaRuntime) { + this.javaRuntime = javaRuntime; + } + + public String getJavaHome() { + return javaHome; + } + + public void setJavaHome(String javaHome) { + this.javaHome = javaHome; + } + + public String getOsName() { + return osName; + } + + public void setOsName(String osName) { + this.osName = osName; + } + + public String getOsArchitecture() { + return osArchitecture; + } + + public void setOsArchitecture(String osArchitecture) { + this.osArchitecture = osArchitecture; + } + + public String getOsVersion() { + return osVersion; + } + + public void setOsVersion(String osVersion) { + this.osVersion = osVersion; + } + + public String getFileEncoding() { + return fileEncoding; + } + + public void setFileEncoding(String fileEncoding) { + this.fileEncoding = fileEncoding; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserDir() { + return userDir; + } + + public void setUserDir(String userDir) { + this.userDir = userDir; + } + + public String getUserTimezone() { + return userTimezone; + } + + public void setUserTimezone(String userTimezone) { + this.userTimezone = userTimezone; + } + + public String getUserLocale() { + return userLocale; + } + + public void setUserLocale(String userLocale) { + this.userLocale = userLocale; + } + + private static String formatUptime(long uptime) { + long diffInSeconds = uptime / 1000; + long diff[] = new long[]{0, 0, 0, 0}; // sec + diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); // min + diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; // hours + diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; // days + diff[0] = (diffInSeconds = (diffInSeconds / 24)); + + return String.format( + "%d day%s, %d hour%s, %d minute%s, %d second%s", + diff[0], + diff[0] != 1 ? "s" : "", + diff[1], + diff[1] != 1 ? "s" : "", + diff[2], + diff[2] != 1 ? "s" : "", + diff[3], + diff[3] != 1 ? "s" : ""); + } + +} From e89499f5db64e198bb0a15ef119720605bb008ff Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Fri, 24 Jul 2015 16:45:27 +0200 Subject: [PATCH 13/14] Fix xmlns for modules in feature packs --- .../system/layers/base/net/iharder/base64/main/module.xml | 4 +--- .../base/org/keycloak/keycloak-adapter-core/main/module.xml | 2 +- .../org/keycloak/keycloak-adapter-subsystem/main/module.xml | 2 +- .../layers/base/org/keycloak/keycloak-core/main/module.xml | 2 +- .../org/keycloak/keycloak-jboss-adapter-core/main/module.xml | 2 +- .../keycloak/keycloak-servlet-oauth-client/main/module.xml | 2 +- .../org/keycloak/keycloak-undertow-adapter/main/module.xml | 2 +- .../base/org/keycloak/keycloak-wf9-subsystem/main/module.xml | 2 +- .../org/keycloak/keycloak-wildfly-adapter/main/module.xml | 2 +- .../system/layers/base/com/google/zxing/core/main/module.xml | 2 +- .../layers/base/com/google/zxing/javase/main/module.xml | 2 +- .../system/layers/base/de/idyl/winzipaes/main/module.xml | 2 +- .../system/layers/base/net/iharder/base64/main/module.xml | 2 +- .../modules/system/layers/base/org/freemarker/main/module.xml | 2 +- .../layers/base/org/jboss/as/product/keycloak/module.xml | 2 +- .../base/org/keycloak/keycloak-account-api/main/module.xml | 2 +- .../org/keycloak/keycloak-account-freemarker/main/module.xml | 2 +- .../base/org/keycloak/keycloak-broker-core/main/module.xml | 2 +- .../base/org/keycloak/keycloak-broker-oidc/main/module.xml | 2 +- .../base/org/keycloak/keycloak-broker-saml/main/module.xml | 2 +- .../org/keycloak/keycloak-connections-file/main/module.xml | 2 +- .../keycloak/keycloak-connections-http-client/main/module.xml | 2 +- .../keycloak/keycloak-connections-infinispan/main/module.xml | 2 +- .../keycloak-connections-jpa-liquibase/main/module.xml | 2 +- .../org/keycloak/keycloak-connections-jpa/main/module.xml | 2 +- .../keycloak-connections-mongo-update/main/module.xml | 2 +- .../org/keycloak/keycloak-connections-mongo/main/module.xml | 2 +- .../base/org/keycloak/keycloak-core-jaxrs/main/module.xml | 2 +- .../layers/base/org/keycloak/keycloak-core/main/module.xml | 2 +- .../base/org/keycloak/keycloak-email-api/main/module.xml | 2 +- .../org/keycloak/keycloak-email-freemarker/main/module.xml | 2 +- .../base/org/keycloak/keycloak-events-api/main/module.xml | 2 +- .../base/org/keycloak/keycloak-events-email/main/module.xml | 2 +- .../keycloak/keycloak-events-jboss-logging/main/module.xml | 2 +- .../base/org/keycloak/keycloak-events-jpa/main/module.xml | 2 +- .../base/org/keycloak/keycloak-events-mongo/main/module.xml | 2 +- .../org/keycloak/keycloak-export-import-api/main/module.xml | 2 +- .../org/keycloak/keycloak-export-import-dir/main/module.xml | 2 +- .../keycloak-export-import-single-file/main/module.xml | 2 +- .../org/keycloak/keycloak-export-import-zip/main/module.xml | 2 +- .../keycloak/keycloak-forms-common-freemarker/main/module.xml | 2 +- .../org/keycloak/keycloak-forms-common-themes/main/module.xml | 2 +- .../keycloak-invalidation-cache-infinispan/main/module.xml | 2 +- .../keycloak-invalidation-cache-model/main/module.xml | 2 +- .../base/org/keycloak/keycloak-js-adapter/main/module.xml | 2 +- .../org/keycloak/keycloak-kerberos-federation/main/module.xml | 2 +- .../org/keycloak/keycloak-ldap-federation/main/module.xml | 2 +- .../base/org/keycloak/keycloak-login-api/main/module.xml | 2 +- .../org/keycloak/keycloak-login-freemarker/main/module.xml | 2 +- .../base/org/keycloak/keycloak-model-api/main/module.xml | 2 +- .../base/org/keycloak/keycloak-model-file/main/module.xml | 2 +- .../base/org/keycloak/keycloak-model-jpa/main/module.xml | 2 +- .../base/org/keycloak/keycloak-model-mongo/main/module.xml | 2 +- .../keycloak-model-sessions-infinispan/main/module.xml | 2 +- .../org/keycloak/keycloak-model-sessions-jpa/main/module.xml | 2 +- .../org/keycloak/keycloak-model-sessions-mem/main/module.xml | 2 +- .../keycloak/keycloak-model-sessions-mongo/main/module.xml | 2 +- .../base/org/keycloak/keycloak-saml-core/main/module.xml | 2 +- .../base/org/keycloak/keycloak-saml-protocol/main/module.xml | 2 +- .../org/keycloak/keycloak-server-subsystem/main/module.xml | 2 +- .../base/org/keycloak/keycloak-services/main/module.xml | 2 +- .../base/org/keycloak/keycloak-social-core/main/module.xml | 2 +- .../org/keycloak/keycloak-social-facebook/main/module.xml | 2 +- .../base/org/keycloak/keycloak-social-github/main/module.xml | 2 +- .../base/org/keycloak/keycloak-social-google/main/module.xml | 2 +- .../org/keycloak/keycloak-social-linkedin/main/module.xml | 2 +- .../keycloak/keycloak-social-stackoverflow/main/module.xml | 2 +- .../base/org/keycloak/keycloak-social-twitter/main/module.xml | 2 +- .../base/org/keycloak/keycloak-timer-api/main/module.xml | 2 +- .../base/org/keycloak/keycloak-timer-basic/main/module.xml | 2 +- .../keycloak/keycloak-wf9-server-subsystem/main/module.xml | 2 +- .../org/keycloak/keycloak-wildfly-extensions/main/module.xml | 2 +- .../modules/system/layers/base/org/liquibase/main/module.xml | 2 +- .../layers/base/org/mongodb/mongo-java-driver/main/module.xml | 2 +- .../modules/system/layers/base/org/twitter4j/main/module.xml | 2 +- .../modules/system/layers/base/sun/jdk/jgss/main/module.xml | 3 +-- 76 files changed, 76 insertions(+), 79 deletions(-) diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml index ba7043089f2..f0d1326c7be 100644 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml @@ -1,8 +1,6 @@ - - - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml index 07dcd06352d..6407abcd191 100644 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml index 4ae8e9a6447..66278bd1d60 100644 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml @@ -22,7 +22,7 @@ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml index b23c5891556..ce36b73e823 100644 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml index 6e5b217ba54..243a5b90983 100644 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-servlet-oauth-client/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-servlet-oauth-client/main/module.xml index 7e75f132572..73fccad06c6 100755 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-servlet-oauth-client/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-servlet-oauth-client/main/module.xml @@ -1,6 +1,6 @@ - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml index 9ba1cb291ad..75ac27ea52a 100644 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-subsystem/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-subsystem/main/module.xml index 5bc59bdf13b..4b2efe5b343 100755 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-subsystem/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-subsystem/main/module.xml @@ -22,7 +22,7 @@ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml index 35a656c15a5..88eaafafb40 100755 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml +++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml index cc18aaaf7af..d2d0ca6983a 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml index b73ba9b34b8..6909121d9b4 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml index 410333d7e94..ef5c336abbb 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml index ba7043089f2..efc692e7866 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml index 2043bef6138..df8dae383c6 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/as/product/keycloak/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/as/product/keycloak/module.xml index 4367111e2ec..d59ccb69653 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/as/product/keycloak/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/as/product/keycloak/module.xml @@ -22,7 +22,7 @@ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml index d36887e584f..ff79ea3da7c 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml index 1512a9e6b93..12a27b49f51 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml index f9837268fbd..148ca83b0ca 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml index 1a75cd11bf6..5f1696b5f0f 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml index 839d9f92fb8..78800f80b58 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml @@ -1,6 +1,6 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml index ef1f1b2eee0..2821a826322 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml index f52288ebd9d..33acbc3fb40 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml index 94a9f1a2f41..6ec7f490c75 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml index 8ade3fd9717..2e001ae3407 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml index ef36ac3d599..befbaca0f83 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml index 621f06d9202..5af24c9c740 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml index 504023f5e51..c1820d0ba8c 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml index c773354615b..359459c75b9 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml index b23c5891556..ce36b73e823 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml index ed433b52c87..7936e57258c 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml index a0c371fb66b..5d7e738c44c 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml index 2f8c152b0c1..6bf4c572546 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml index 255f8302b47..8c924b9464a 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml index 5a6fe2b92ba..cb3911e6bf7 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml index 12c859e74c4..51820cbba4b 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml index 4e48e7f69b8..58f4ef6613d 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml index 2e503352f7e..f93fac08e3f 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml index 1cda32b5ee6..e07d83a7d0e 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml index a390929490f..75bfd6abea4 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml index a33365dfd3a..ef9dfb3eaf3 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml index c6c63253754..9c2d04519bc 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml index 0e12a97f6fe..b6bb215b015 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml index 572ab38840e..1fbd5a83b3e 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml index 1844bc806f0..8136f8338be 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml index d99ac75cad2..7f8c1eec757 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml index 4f9da8b55c0..620c79701fe 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml index e8c9e4dbd83..b1bd769a2cf 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml index ff6f6ac456d..137514de0cb 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml index 1cb5c4182ee..ba3b629c0ef 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml index 14a0a869c6a..356057622f3 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml index e3ae276601b..d21a5372fc8 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml index 4f50b7ad1db..4e62ca71f8d 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml index 702406c95da..9c99b579906 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml index 23f94b144d0..877f0611734 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml index 20330699574..39490fc4731 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml index 6a1d1019ca6..47c9d408bea 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml index 69936807f81..0b5aaa05bd8 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml index c09490e1808..8c7846991b7 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml index fc0cd15d47e..03a5633d1fe 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml index b0309bdb6b1..d6e7d81f6af 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml @@ -22,7 +22,7 @@ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml index 4917ab6a472..5b556022470 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml index 836d5d6b5b4..47a1348ba66 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml index 4c22779011a..30a2489b3ad 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml index 9197bb0c961..6a8e0c3276f 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml index bb56189ffd1..965a0e48e49 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml index db385431c97..3bba4a8d6b6 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml index 5af13cef391..a1ac0830a9d 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml index cf56209f4a8..f07af8b2219 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml index 77049169adc..af13ac0a9f1 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml index e2279f9a3a0..1ee1936fd91 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-server-subsystem/main/module.xml index 430bb0af4d8..6748cb4237e 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-server-subsystem/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wf9-server-subsystem/main/module.xml @@ -22,7 +22,7 @@ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml index 556769e366f..58d5184390a 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml @@ -1,5 +1,5 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml index d75eef002a8..db707e84346 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml index bb4acdd80e6..2cb5fbe47d8 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml index 70b84dcc781..9dc34a573fd 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml @@ -2,7 +2,7 @@ - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/sun/jdk/jgss/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/sun/jdk/jgss/main/module.xml index 6df03ff4ba0..100d65d0813 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/sun/jdk/jgss/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/sun/jdk/jgss/main/module.xml @@ -2,9 +2,8 @@ - + - From 5d075a97ddd8cba19c0ec6eca768d7d290593f66 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Fri, 24 Jul 2015 16:45:58 +0200 Subject: [PATCH 14/14] Fixes to server-info --- .../admin/resources/js/controllers/clients.js | 2 +- .../partials/server-info-providers.html | 2 +- .../admin/info/ServerInfoAdminResource.java | 23 +++++++++-- .../testsuite/admin/AdminAPITest.java | 39 ++++--------------- 4 files changed, 28 insertions(+), 38 deletions(-) diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js index 8ad8ae646ed..810aef73a7b 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js @@ -549,7 +549,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se "bearer-only" ]; - $scope.protocols = Object.keys(serverInfo.providers['login-protocol'].providers); + $scope.protocols = Object.keys(serverInfo.providers['login-protocol'].providers).sort(); $scope.signatureAlgorithms = [ "RSA_SHA1", diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html index 6f8bbb49d7a..aa95b5016f1 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info-providers.html @@ -28,7 +28,7 @@ - + {{spi.name}}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java index 8223556b188..fd0afc9615f 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java @@ -60,12 +60,27 @@ public class ServerInfoAdminResource { } private void setProviders(ServerInfoRepresentation info) { - Map spis = new HashMap<>(); + LinkedHashMap spiReps = new LinkedHashMap<>(); + + List spis = new LinkedList<>(); for (Spi spi : ServiceLoader.load(Spi.class)) { + spis.add(spi); + } + Collections.sort(spis, new Comparator() { + @Override + public int compare(Spi s1, Spi s2) { + return s1.getName().compareTo(s2.getName()); + } + }); + + for (Spi spi : spis) { SpiInfoRepresentation spiRep = new SpiInfoRepresentation(); spiRep.setInternal(spi.isInternal()); spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass())); - Set providerIds = session.listProviderIds(spi.getProviderClass()); + + List providerIds = new LinkedList<>(session.listProviderIds(spi.getProviderClass())); + Collections.sort(providerIds); + Map providers = new HashMap<>(); if (providerIds != null) { @@ -79,9 +94,9 @@ public class ServerInfoAdminResource { } spiRep.setProviders(providers); - spis.put(spi.getName(), spiRep); + spiReps.put(spi.getName(), spiRep); } - info.setProviders(spis); + info.setProviders(spiReps); } private void setThemes(ServerInfoRepresentation info) { 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 33ead317e41..dc49661c381 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 @@ -299,7 +299,6 @@ public class AdminAPITest { @Test public void testServerInfo() { - String token = createToken(); final String authHeader = "Bearer " + token; ClientRequestFilter authFilter = new ClientRequestFilter() { @@ -314,45 +313,21 @@ public class AdminAPITest { Map response = target.request().accept("application/json").get(Map.class); + + System.out.println(response.keySet().toString()); + Assert.assertNotNull(response); - Assert.assertEquals(Version.VERSION, response.get("version")); - Assert.assertNotNull(response.get("serverTime")); Assert.assertNotNull(response.get("providers")); Assert.assertNotNull(response.get("themes")); Assert.assertNotNull(response.get("enums")); - // System.out.println(response); - - } - - @Test - public void testServerInfoPage() { - - String token = createToken(); - final String authHeader = "Bearer " + token; - ClientRequestFilter authFilter = new ClientRequestFilter() { - @Override - public void filter(ClientRequestContext requestContext) throws IOException { - requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); - } - }; - Client client = ClientBuilder.newBuilder().register(authFilter).build(); - UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); - WebTarget target = client.target(AdminRoot.adminBaseUrl(authBase).path("serverinfopage")); - - Map response = target.request().accept("application/json").get(Map.class); - - Assert.assertNotNull(response); - Assert.assertEquals(Version.VERSION, response.get("version")); - Assert.assertNotNull(response.get("serverTime")); - Assert.assertNotNull(response.get("providers")); - Assert.assertNotNull(response.get("serverStartupTime")); - Assert.assertNotNull(response.get("memoryInfo")); Assert.assertNotNull(response.get("systemInfo")); - - // System.out.println(response); + Map systemInfo = (Map) response.get("systemInfo"); + Assert.assertEquals(Version.VERSION, systemInfo.get("version")); + Assert.assertNotNull(systemInfo.get("serverTime")); + Assert.assertNotNull(systemInfo.get("uptime")); } }