Compare commits

..
Author SHA1 Message Date
Stian Thorgersen 3b071b83aa Version bump 2015-01-22 19:04:46 +01:00
Stian Thorgersen eef6e94923 KEYCLOAK-977 Use reflection to find constructor for JBossGenericPrincipal to support EAP 6.4
Conflicts:
	integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java
2015-01-22 16:24:07 +01:00
Stian Thorgersen f6d50245ac KEYCLOAK-820 Don't expose realm private key through admin endpoints
Conflicts:
	model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
2015-01-22 16:15:21 +01:00
Stian Thorgersen f3940bf78c Fix broken symbol 2015-01-22 16:09:01 +01:00
Stian Thorgersen 62bcf17a1e Merge pull request #825 from matzew/ReducingLogLevel
setting 'Bearer role' loglevel to debug
2014-10-31 12:33:36 +01:00
Matthias Wessendorf 44f9b28618 setting 'Bearer role' loglevel to debug 2014-10-31 11:44:25 +01:00
Stian Thorgersen 9ec0409a46 Merge pull request #814 from stianst/Branch_1_0
Version bump
2014-10-29 14:32:49 +01:00
Stian Thorgersen cd5e191b18 Version bump 2014-10-29 14:32:23 +01:00
Stian Thorgersen a14b3753da Merge pull request #813 from stianst/Branch_1_0
Branch 1 0
2014-10-29 14:22:15 +01:00
Stian Thorgersen 41b8701d51 KEYCLOAK-763
Document reverse proxy setup on AS7/EAP
2014-10-29 14:04:43 +01:00
Stian Thorgersen d84e7eb38b KEYCLOAK-797
login-status-iframe.html fails if domain contains hyphen
2014-10-29 14:03:48 +01:00
Stian Thorgersen d40b256557 Version bump 2014-10-29 14:03:40 +01:00
Stian Thorgersen 5304e197e5 KEYCLOAK-747 2014-10-27 15:02:36 +01:00
Stian Thorgersen 623e28b9c2 Fixes to testsuite for db cleanup 2014-10-27 13:46:03 +01:00
Stian Thorgersen 274bc4e33a Added liquibase to clean db for testsuite only 2014-10-27 08:33:24 +01:00
Stian Thorgersen 42b44ed3b0 Version bump 2014-10-27 08:33:18 +01:00
Stian Thorgersen b0c99e6111 KEYCLOAK-786
Value in input fields should be escaped
2014-10-27 08:33:13 +01:00
Stian Thorgersen fe73feee34 Merge pull request #788 from stianst/Branch_1_0
KEYCLOAK-711 HttpServletReqest.logout() does not work with relative URI
2014-10-21 12:43:03 +02:00
Stian Thorgersen 629d3ce4aa KEYCLOAK-711 HttpServletReqest.logout() does not work with relative URI 2014-10-21 12:36:46 +02:00
Stian Thorgersen ed6c290bbc Merge pull request #785 from stianst/Branch_1_0
KEYCLOAK-710 Ignore missing roles in access-code
2014-10-21 11:24:50 +02:00
Stian Thorgersen 9dde3f60d6 KEYCLOAK-710 Ignore missing roles in access-code 2014-10-21 11:09:43 +02:00
Stian Thorgersen 1bcc8c9110 Merge pull request #781 from stianst/Branch_1_0
Fixes
2014-10-21 10:02:12 +02:00
Stian Thorgersen bb132e1aa0 KEYCLOAK-765 Check signature on state in social callback 2014-10-20 13:29:45 +02:00
Stian Thorgersen 5e4b843eb7 KEYCLOAK-700 Check path is valid in account/login-redirect 2014-10-20 13:12:23 +02:00
Stian Thorgersen 85cc63c7ce KEYCLOAK-703 Check valid origin is passed to login-status-iframe
Conflicts:
	services/src/main/java/org/keycloak/services/resources/TokenService.java
2014-10-20 13:12:08 +02:00
Stian Thorgersen a697f4bd41 KEYCLOAK-699 Set maximum size of qr-code 2014-10-20 13:03:05 +02:00
Stian Thorgersen 7e03c74bc3 KEYCLOAK-747 Fix onUserRemoved in user session providers
Conflicts:
	model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
	model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
	model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java
	model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
	testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
2014-10-17 13:34:12 +02:00
Stian Thorgersen 67f7bcec99 Version bump 2014-10-08 15:36:53 +02:00
Stian Thorgersen 267b80c2fa Fix adding attributes to users over rest 2014-10-08 12:11:28 +02:00
Stian Thorgersen 66e848710e Merge pull request #748 from stianst/Branch_1_0
Version bump
2014-10-08 11:11:37 +02:00
Stian Thorgersen 93f48ecb6c Version bump 2014-10-08 09:30:30 +02:00
Stian Thorgersen ecace349f5 Merge pull request #740 from stianst/Branch_1_0
KEYCLOAK-729
2014-10-03 14:12:10 +02:00
Stian Thorgersen 4a5b313816 KEYCLOAK-729
Update themes documentation
2014-10-03 14:11:27 +02:00
Stian Thorgersen c79506a34f Merge pull request #738 from stianst/Branch_1_0
Fixes
2014-10-03 13:24:45 +02:00
Stian Thorgersen 5e97051c07 KEYCLOAK-722 Refreshing token throws RuntimeException if realm keys have changed
Conflicts:
	testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java

Backport changes to AssertEvents
2014-10-03 13:23:07 +02:00
Stian Thorgersen 562aa24ebf KEYCLOAK-662 NPE when using direct grant API with email as username 2014-10-03 13:23:07 +02:00
Stian Thorgersen 4a66687304 Merge pull request #735 from stianst/Branch_1_0
KEYCLOAK-701 Use built-in themes if specified theme is not found
2014-10-03 11:27:48 +02:00
Stian Thorgersen 42c2066fd8 KEYCLOAK-701 Use built-in themes if specified theme is not found 2014-10-03 11:16:50 +02:00
Stian Thorgersen 161b3293dc Merge pull request #732 from stianst/Branch_1_0
KEYCLOAK-732 AuthenticationManager.logout should logout just current use...
2014-10-03 11:02:29 +02:00
mposolda a9608904d0 KEYCLOAK-732 AuthenticationManager.logout should logout just current userSession
Backport multi-session tests to 1.0.x
2014-10-03 11:01:47 +02:00
mposolda 1b9358c4c6 KEYCLOAK-709 ResourceAdminManager.logoutApplication shouldn't immediatelly fail with RuntimeException 2014-10-02 13:34:00 +02:00
Stian Thorgersen 70ff6c7209 Merge pull request #726 from lfryc/KEYCLOAK-727-log-out-all-sessions
KEYCLOAK-727: 'logout'->'log out' + moved message to bundle
2014-10-02 10:54:02 +02:00
Lukas Fryc 3133e30265 KEYCLOAK-727: 'logout'->'log out' + moved message to bundle 2014-10-02 09:54:45 +02:00
Stian Thorgersen d0c2e80949 KEYCLOAK-725 Add realm update to the Admin Client 2014-10-01 14:53:08 +02:00
Stian Thorgersen 89e1937501 Update version 2014-10-01 14:50:35 +02:00
1177 changed files with 7523 additions and 50672 deletions

No files matched your search

-6
View File
@@ -9,12 +9,6 @@
.settings
.classpath
# NetBeans #
############
nbactions.xml
nb-configuration.xml
catalog.xml
# Compiled source #
###################
*.com
-8
View File
@@ -1,8 +0,0 @@
language: java
cache:
directories:
- $HOME/.m2
sudo: false
after_script: 'misc/.travis/after.sh'
+3 -4
View File
@@ -5,14 +5,14 @@ Please visit [http://keycloak.org](http://keycloak.org) for more information on
and video tutorials.
Keycloak is an SSO Service for web apps and REST services.
It can be used for social applications as well as enterprise applications. It is based on OpenID Connect with support for SAML 2.0 as well.
It can be used for social applications as well as enterprise applications. It is based on OpenID Connect with SAML support in the works.
Here's some of the features:
* SSO and Single Log Out for browser applications
* Social Broker. Enable Google, Facebook, Yahoo, Twitter social login with no code required.
* Optional LDAP/Active Directory integration
* Optional User Registration
* Password and TOTP support (via Google Authenticator or FreeOTP). Client cert auth coming soon.
* Password and TOTP support (via Google Authenticator). Client cert auth coming soon.
* User session management from both admin and user perspective
* Customizable themes for user facing pages: login, grant pages, account management, emails, and admin console all customizable!
* OAuth Bearer token auth for REST Services
@@ -24,13 +24,12 @@ Here's some of the features:
* Completely centrally managed user and role mapping metadata. Minimal configuration at the application side
* Admin Console for managing users, roles, role mappings, applications, user sessions, allowed CORS web origins, and OAuth clients.
* Deployable as a WAR, appliance, or an Openshift cloud service (SaaS).
* Supports JBoss AS7, EAP 6.x, Wildfly, Tomcat, and Jetty applications. Plans to support Node.js, RAILS, GRAILS, and other non-Java applications.
* Supports JBoss AS7, EAP 6.x, and Wildfly applications. Plans to support Node.js, RAILS, GRAILS, and other non-Java applications.
* Javascript/HTML 5 adapter for pure Javascript apps
* Session management from admin console
* Revocation policies
* Password policies
* OpenID Connect Support
* SAML Support
Please visit [http://keycloak.org](http://keycloak.org) for more information on Keycloak including how to download, documentation,
and video tutorials.
-33
View File
@@ -1,33 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-connections-infinispan</artifactId>
<name>Keycloak Connections Infinispan</name>
<description/>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -1,26 +0,0 @@
package org.keycloak.connections.infinispan;
import org.infinispan.Cache;
import org.infinispan.manager.EmbeddedCacheManager;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class DefaultInfinispanConnectionProvider implements InfinispanConnectionProvider {
private EmbeddedCacheManager cacheManager;
public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public <K, V> Cache<K, V> getCache(String name) {
return cacheManager.getCache(name);
}
@Override
public void close() {
}
}
@@ -1,123 +0,0 @@
package org.keycloak.connections.infinispan;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import javax.naming.InitialContext;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory {
protected static final Logger logger = Logger.getLogger(DefaultInfinispanConnectionProviderFactory.class);
private Config.Scope config;
private EmbeddedCacheManager cacheManager;
private boolean containerManaged;
@Override
public InfinispanConnectionProvider create(KeycloakSession session) {
lazyInit();
return new DefaultInfinispanConnectionProvider(cacheManager);
}
@Override
public void close() {
if (cacheManager != null && !containerManaged) {
cacheManager.stop();
}
cacheManager = null;
}
@Override
public String getId() {
return "default";
}
@Override
public void init(Config.Scope config) {
this.config = config;
}
private void lazyInit() {
if (cacheManager == null) {
synchronized (this) {
if (cacheManager == null) {
String cacheContainer = config.get("cacheContainer");
if (cacheContainer != null) {
initContainerManaged(cacheContainer);
} else {
initEmbedded();
}
}
}
}
}
private void initContainerManaged(String cacheContainerLookup) {
try {
cacheManager = (EmbeddedCacheManager) new InitialContext().lookup(cacheContainerLookup);
containerManaged = true;
logger.debugv("Using container managed Infinispan cache container, lookup={1}", cacheContainerLookup);
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve cache container", e);
}
}
private void initEmbedded() {
GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
boolean clustered = config.getBoolean("clustered", false);
boolean async = config.getBoolean("async", true);
if (clustered) {
gcb.transport().defaultTransport();
}
cacheManager = new DefaultCacheManager(gcb.build());
containerManaged = false;
logger.debug("Started embedded Infinispan cache container");
ConfigurationBuilder invalidationConfigBuilder = new ConfigurationBuilder();
if (clustered) {
invalidationConfigBuilder.clustering().cacheMode(async ? CacheMode.INVALIDATION_ASYNC : CacheMode.INVALIDATION_SYNC);
}
Configuration invalidationCacheConfiguration = invalidationConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, invalidationCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_CACHE_NAME, invalidationCacheConfiguration);
ConfigurationBuilder sessionConfigBuilder = new ConfigurationBuilder();
if (clustered) {
String sessionsMode = config.get("sessionsMode", "distributed");
if (sessionsMode.equalsIgnoreCase("replicated")) {
sessionConfigBuilder.clustering().cacheMode(async ? CacheMode.REPL_ASYNC : CacheMode.REPL_SYNC);
} else if (sessionsMode.equalsIgnoreCase("distributed")) {
sessionConfigBuilder.clustering().cacheMode(async ? CacheMode.DIST_ASYNC : CacheMode.DIST_SYNC);
} else {
throw new RuntimeException("Invalid value for sessionsMode");
}
sessionConfigBuilder.clustering().hash()
.numOwners(config.getInt("sessionsOwners", 2))
.numSegments(config.getInt("sessionsSegments", 60)).build();
}
Configuration sessionCacheConfiguration = sessionConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
}
}
@@ -1,18 +0,0 @@
package org.keycloak.connections.infinispan;
import org.infinispan.Cache;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface InfinispanConnectionProvider extends Provider {
static final String REALM_CACHE_NAME = "realms";
static final String USER_CACHE_NAME = "users";
static final String SESSION_CACHE_NAME = "sessions";
static final String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
<K, V> Cache<K, V> getCache(String name);
}
@@ -1,9 +0,0 @@
package org.keycloak.connections.infinispan;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface InfinispanConnectionProviderFactory extends ProviderFactory<InfinispanConnectionProvider> {
}
@@ -1,27 +0,0 @@
package org.keycloak.connections.infinispan;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class InfinispanConnectionSpi implements Spi {
@Override
public String getName() {
return "connectionsInfinispan";
}
@Override
public Class<? extends Provider> getProviderClass() {
return InfinispanConnectionProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return InfinispanConnectionProviderFactory.class;
}
}
@@ -1 +0,0 @@
org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory
@@ -1 +0,0 @@
org.keycloak.connections.infinispan.InfinispanConnectionSpi
-72
View File
@@ -1,72 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-connections-jpa-liquibase</artifactId>
<name>Keycloak Connections JPA Liquibase Updater</name>
<description/>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-connections-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<configuration>
<changeLogFile>META-INF/jpa-changelog-master.xml</changeLogFile>
<url>${url}</url>
<driver>${driver}</driver>
<username>${username}</username>
<password>${password}</password>
<referenceUrl>${referenceUrl}</referenceUrl>
<referenceDriver>${driver}</referenceDriver>
<referenceUsername>${username}</referenceUsername>
<referencePassword>${password}</referencePassword>
</configuration>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<properties>
<username>sa</username>
<password></password>
<driver>org.h2.Driver</driver>
</properties>
</project>
@@ -1,224 +0,0 @@
package org.keycloak.connections.jpa.updater.liquibase;
import liquibase.Contexts;
import liquibase.Liquibase;
import liquibase.changelog.ChangeSet;
import liquibase.changelog.DatabaseChangeLog;
import liquibase.changelog.RanChangeSet;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.core.DB2Database;
import liquibase.database.core.DerbyDatabase;
import liquibase.database.core.FirebirdDatabase;
import liquibase.database.core.H2Database;
import liquibase.database.core.HsqlDatabase;
import liquibase.database.core.InformixDatabase;
import liquibase.database.core.MSSQLDatabase;
import liquibase.database.core.MySQLDatabase;
import liquibase.database.core.OracleDatabase;
import liquibase.database.core.PostgresDatabase;
import liquibase.database.core.SQLiteDatabase;
import liquibase.database.core.SybaseASADatabase;
import liquibase.database.core.SybaseDatabase;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.logging.LogFactory;
import liquibase.logging.LogLevel;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.servicelocator.ServiceLocator;
import org.jboss.logging.Logger;
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
private static final Logger logger = Logger.getLogger(LiquibaseJpaUpdaterProvider.class);
private static final String CHANGELOG = "META-INF/jpa-changelog-master.xml";
@Override
public String getCurrentVersionSql() {
return "SELECT ID from DATABASECHANGELOG ORDER BY DATEEXECUTED DESC LIMIT 1";
}
@Override
public void update(Connection connection) {
logger.debug("Starting database update");
try {
Liquibase liquibase = getLiquibase(connection);
List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
if (!changeSets.isEmpty()) {
if (changeSets.get(0).getId().equals(FIRST_VERSION)) {
Statement statement = connection.createStatement();
try {
statement.executeQuery("SELECT id FROM REALM");
logger.infov("Updating database from {0} to {1}", FIRST_VERSION, changeSets.get(changeSets.size() - 1).getId());
liquibase.markNextChangeSetRan((Contexts) null);
} catch (SQLException e) {
logger.info("Initializing database schema");
}
} else {
if (logger.isDebugEnabled()) {
List<RanChangeSet> ranChangeSets = liquibase.getDatabase().getRanChangeSetList();
logger.debugv("Updating database from {0} to {1}", ranChangeSets.get(ranChangeSets.size() - 1).getId(), changeSets.get(changeSets.size() - 1).getId());
} else {
logger.infov("Updating database");
}
}
liquibase.update((Contexts) null);
}
} catch (Exception e) {
throw new RuntimeException("Failed to update database", e);
}
logger.debug("Completed database update");
}
@Override
public void validate(Connection connection) {
try {
Liquibase liquibase = getLiquibase(connection);
liquibase.validate();
} catch (Exception e) {
throw new RuntimeException("Failed to validate database", e);
}
}
private Liquibase getLiquibase(Connection connection) throws Exception {
ServiceLocator sl = ServiceLocator.getInstance();
if (!System.getProperties().containsKey("liquibase.scan.packages")) {
if (sl.getPackages().remove("liquibase.core")) {
sl.addPackageToScan("liquibase.core.xml");
}
if (sl.getPackages().remove("liquibase.parser")) {
sl.addPackageToScan("liquibase.parser.core.xml");
}
if (sl.getPackages().remove("liquibase.serializer")) {
sl.addPackageToScan("liquibase.serializer.core.xml");
}
sl.getPackages().remove("liquibase.ext");
sl.getPackages().remove("liquibase.sdk");
}
LogFactory.setInstance(new LogWrapper());
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
return new Liquibase(CHANGELOG, new ClassLoaderResourceAccessor(getClass().getClassLoader()), database);
}
@Override
public void close() {
}
private static class LogWrapper extends LogFactory {
private liquibase.logging.Logger logger = new liquibase.logging.Logger() {
@Override
public void setName(String name) {
}
@Override
public void setLogLevel(String level) {
}
@Override
public void setLogLevel(LogLevel level) {
}
@Override
public void setLogLevel(String logLevel, String logFile) {
}
@Override
public void severe(String message) {
LiquibaseJpaUpdaterProvider.logger.error(message);
}
@Override
public void severe(String message, Throwable e) {
LiquibaseJpaUpdaterProvider.logger.error(message, e);
}
@Override
public void warning(String message) {
LiquibaseJpaUpdaterProvider.logger.warn(message);
}
@Override
public void warning(String message, Throwable e) {
LiquibaseJpaUpdaterProvider.logger.warn(message, e);
}
@Override
public void info(String message) {
LiquibaseJpaUpdaterProvider.logger.debug(message);
}
@Override
public void info(String message, Throwable e) {
LiquibaseJpaUpdaterProvider.logger.debug(message, e);
}
@Override
public void debug(String message) {
LiquibaseJpaUpdaterProvider.logger.trace(message);
}
@Override
public LogLevel getLogLevel() {
if (LiquibaseJpaUpdaterProvider.logger.isTraceEnabled()) {
return LogLevel.DEBUG;
} else if (LiquibaseJpaUpdaterProvider.logger.isDebugEnabled()) {
return LogLevel.INFO;
} else {
return LogLevel.WARNING;
}
}
@Override
public void debug(String message, Throwable e) {
LiquibaseJpaUpdaterProvider.logger.trace(message, e);
}
@Override
public void setChangeLog(DatabaseChangeLog databaseChangeLog) {
}
@Override
public void setChangeSet(ChangeSet changeSet) {
}
@Override
public int getPriority() {
return 0;
}
};
@Override
public liquibase.logging.Logger getLog(String name) {
return logger;
}
@Override
public liquibase.logging.Logger getLog() {
return logger;
}
}
}
@@ -1,31 +0,0 @@
package org.keycloak.connections.jpa.updater.liquibase;
import org.keycloak.Config;
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory;
import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class LiquibaseJpaUpdaterProviderFactory implements JpaUpdaterProviderFactory {
@Override
public JpaUpdaterProvider create(KeycloakSession session) {
return new LiquibaseJpaUpdaterProvider();
}
@Override
public void init(Config.Scope config) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "liquibase";
}
}
@@ -1,85 +0,0 @@
package org.keycloak.connections.jpa.updater.liquibase.custom;
import liquibase.change.custom.CustomSqlChange;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.CustomChangeException;
import liquibase.exception.SetupException;
import liquibase.exception.ValidationErrors;
import liquibase.resource.ResourceAccessor;
import liquibase.snapshot.SnapshotGeneratorFactory;
import liquibase.statement.SqlStatement;
import liquibase.statement.core.UpdateStatement;
import liquibase.structure.core.Schema;
import liquibase.structure.core.Table;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class AddRealmCodeSecret implements CustomSqlChange {
private String confirmationMessage;
@Override
public SqlStatement[] generateStatements(Database database) throws CustomChangeException {
try {
StringBuilder sb = new StringBuilder();
sb.append("Generated codeSecret for realms: ");
Connection connection = ((JdbcConnection) (database.getConnection())).getWrappedConnection();
ArrayList<SqlStatement> statements = new ArrayList<SqlStatement>();
String correctedTableName = database.correctObjectName("REALM", Table.class);
if (SnapshotGeneratorFactory.getInstance().has(new Table().setName(correctedTableName), database)) {
ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM REALM WHERE CODE_SECRET IS NULL");
while (resultSet.next()) {
String id = resultSet.getString(1);
UpdateStatement statement = new UpdateStatement(null, null, correctedTableName)
.addNewColumnValue("CODE_SECRET", KeycloakModelUtils.generateCodeSecret())
.setWhereClause("ID='" + id + "'");
statements.add(statement);
if (!resultSet.isFirst()) {
sb.append(", ");
}
sb.append(id);
}
if (!statements.isEmpty()) {
confirmationMessage = sb.toString();
}
}
return statements.toArray(new SqlStatement[statements.size()]);
} catch (Exception e) {
throw new CustomChangeException("Failed to add realm code secret", e);
}
}
@Override
public String getConfirmationMessage() {
return confirmationMessage;
}
@Override
public void setUp() throws SetupException {
}
@Override
public void setFileOpener(ResourceAccessor resourceAccessor) {
}
@Override
public ValidationErrors validate(Database database) {
return null;
}
}
@@ -1,420 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
<changeSet author="sthorger@redhat.com" id="1.0.0.Final">
<createTable tableName="APPLICATION_DEFAULT_ROLES">
<column name="APPLICATION_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="ROLE_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="CLIENT">
<column name="DTYPE" type="VARCHAR(31)">
<constraints nullable="false"/>
</column>
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="ALLOWED_CLAIMS_MASK" type="BIGINT"/>
<column name="ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="FULL_SCOPE_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="NAME" type="VARCHAR(255)"/>
<column name="NOT_BEFORE" type="INT"/>
<column name="PUBLIC_CLIENT" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="SECRET" type="VARCHAR(255)"/>
<column name="BASE_URL" type="VARCHAR(255)"/>
<column name="BEARER_ONLY" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="MANAGEMENT_URL" type="VARCHAR(255)"/>
<column name="SURROGATE_AUTH_REQUIRED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="DIRECT_GRANTS_ONLY" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="REALM_ID" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="CLIENT_SESSION">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="ACTION" type="INT"/>
<column name="CLIENT_ID" type="VARCHAR(36)"/>
<column name="REDIRECT_URI" type="VARCHAR(255)"/>
<column name="STATE" type="VARCHAR(255)"/>
<column name="TIMESTAMP" type="INT"/>
<column name="SESSION_ID" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="CLIENT_SESSION_ROLE">
<column name="ROLE_ID" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="CLIENT_SESSION" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="COMPOSITE_ROLE">
<column name="COMPOSITE" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="CHILD_ROLE" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="CREDENTIAL">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="DEVICE" type="VARCHAR(255)"/>
<column name="HASH_ITERATIONS" type="INT"/>
<column name="SALT" type="BLOB(16)"/>
<column name="TYPE" type="VARCHAR(255)"/>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="USER_ID" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="EVENT_ENTITY">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="CLIENT_ID" type="VARCHAR(255)"/>
<column name="DETAILS_JSON" type="VARCHAR(2550)"/>
<column name="ERROR" type="VARCHAR(255)"/>
<column name="IP_ADDRESS" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(255)"/>
<column name="SESSION_ID" type="VARCHAR(255)"/>
<column name="TIME" type="BIGINT"/>
<column name="TYPE" type="VARCHAR(255)"/>
<column name="USER_ID" type="VARCHAR(255)"/>
</createTable>
<createTable tableName="FED_PROVIDERS">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="USERFEDERATIONPROVIDERS_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="KEYCLOAK_ROLE">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="APP_REALM_CONSTRAINT" type="VARCHAR(36)"/>
<column name="APPLICATION_ROLE" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="DESCRIPTION" type="VARCHAR(255)"/>
<column name="NAME" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(255)"/>
<column name="APPLICATION" type="VARCHAR(36)"/>
<column name="REALM" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="REALM">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="ACCESS_CODE_LIFESPAN" type="INT"/>
<column name="USER_ACTION_LIFESPAN" type="INT"/>
<column name="ACCESS_TOKEN_LIFESPAN" type="INT"/>
<column name="ACCOUNT_THEME" type="VARCHAR(255)"/>
<column name="ADMIN_THEME" type="VARCHAR(255)"/>
<column name="EMAIL_THEME" type="VARCHAR(255)"/>
<column name="ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="EVENTS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="EVENTS_EXPIRATION" type="BIGINT"/>
<column name="LOGIN_THEME" type="VARCHAR(255)"/>
<column name="NAME" type="VARCHAR(255)"/>
<column name="NOT_BEFORE" type="INT"/>
<column name="PASSWORD_CRED_GRANT_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="PASSWORD_POLICY" type="VARCHAR(255)"/>
<column name="PRIVATE_KEY" type="VARCHAR(2048)"/>
<column name="PUBLIC_KEY" type="VARCHAR(2048)"/>
<column name="REGISTRATION_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="REMEMBER_ME" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="RESET_PASSWORD_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="SOCIAL" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="SSL_REQUIRED" type="VARCHAR(255)"/>
<column name="SSO_IDLE_TIMEOUT" type="INT"/>
<column name="SSO_MAX_LIFESPAN" type="INT"/>
<column name="UPDATE_PROFILE_ON_SOC_LOGIN" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="VERIFY_EMAIL" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="MASTER_ADMIN_APP" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="REALM_APPLICATION">
<column name="APPLICATION_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="REALM_ATTRIBUTE">
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="REALM_DEFAULT_ROLES">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="ROLE_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="REALM_EVENTS_LISTENERS">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
</createTable>
<createTable tableName="REALM_REQUIRED_CREDENTIAL">
<column name="TYPE" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="FORM_LABEL" type="VARCHAR(255)"/>
<column name="INPUT" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="SECRET" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="REALM_SMTP_CONFIG">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="REALM_SOCIAL_CONFIG">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="REDIRECT_URIS">
<column name="CLIENT_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
</createTable>
<createTable tableName="SCOPE_MAPPING">
<column name="CLIENT_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="ROLE_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="USERNAME_LOGIN_FAILURE">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="USERNAME" type="VARCHAR(200)">
<constraints nullable="false"/>
</column>
<column name="FAILED_LOGIN_NOT_BEFORE" type="INT"/>
<column name="LAST_FAILURE" type="BIGINT"/>
<column name="LAST_IP_FAILURE" type="VARCHAR(255)"/>
<column name="NUM_FAILURES" type="INT"/>
</createTable>
<createTable tableName="USER_ATTRIBUTE">
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="USER_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="USER_ENTITY">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="EMAIL" type="VARCHAR(255)"/>
<column name="EMAIL_CONSTRAINT" type="VARCHAR(255)"/>
<column name="EMAIL_VERIFIED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="FEDERATION_LINK" type="VARCHAR(255)"/>
<column name="FIRST_NAME" type="VARCHAR(255)"/>
<column name="LAST_NAME" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(255)"/>
<column name="TOTP" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="USERNAME" type="VARCHAR(255)"/>
</createTable>
<createTable tableName="USER_FEDERATION_CONFIG">
<column name="USER_FEDERATION_PROVIDER_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="USER_FEDERATION_PROVIDER">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="CHANGED_SYNC_PERIOD" type="INT"/>
<column name="DISPLAY_NAME" type="VARCHAR(255)"/>
<column name="FULL_SYNC_PERIOD" type="INT"/>
<column name="LAST_SYNC" type="INT"/>
<column name="PRIORITY" type="INT"/>
<column name="PROVIDER_NAME" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="USER_REQUIRED_ACTION">
<column name="ACTION" type="INT">
<constraints nullable="false"/>
</column>
<column name="USER_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="USER_ROLE_MAPPING">
<column name="ROLE_ID" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="USER_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="USER_SESSION">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="AUTH_METHOD" type="VARCHAR(255)"/>
<column name="IP_ADDRESS" type="VARCHAR(255)"/>
<column name="LAST_SESSION_REFRESH" type="INT"/>
<column name="LOGIN_USERNAME" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(255)"/>
<column name="REMEMBER_ME" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="STARTED" type="INT"/>
<column name="USER_ID" type="VARCHAR(255)"/>
</createTable>
<createTable tableName="USER_SOCIAL_LINK">
<column name="SOCIAL_PROVIDER" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="REALM_ID" type="VARCHAR(255)"/>
<column name="SOCIAL_USER_ID" type="VARCHAR(255)"/>
<column name="SOCIAL_USERNAME" type="VARCHAR(255)"/>
<column name="USER_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="WEB_ORIGINS">
<column name="CLIENT_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
</createTable>
<addPrimaryKey columnNames="REALM_ID, NAME" constraintName="CONSTRAINT_1" tableName="REALM_SOCIAL_CONFIG"/>
<addPrimaryKey columnNames="REALM_ID, USERNAME" constraintName="CONSTRAINT_17" tableName="USERNAME_LOGIN_FAILURE"/>
<addPrimaryKey columnNames="ACTION, USER_ID" constraintName="CONSTRAINT_2" tableName="USER_REQUIRED_ACTION"/>
<addPrimaryKey columnNames="SOCIAL_PROVIDER, USER_ID" constraintName="CONSTRAINT_3" tableName="USER_SOCIAL_LINK"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_4" tableName="EVENT_ENTITY"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_4A" tableName="REALM"/>
<addPrimaryKey columnNames="CLIENT_SESSION, ROLE_ID" constraintName="CONSTRAINT_5" tableName="CLIENT_SESSION_ROLE"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_57" tableName="USER_SESSION"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_5C" tableName="USER_FEDERATION_PROVIDER"/>
<addPrimaryKey columnNames="NAME, USER_ID" constraintName="CONSTRAINT_6" tableName="USER_ATTRIBUTE"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_7" tableName="CLIENT"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_8" tableName="CLIENT_SESSION"/>
<addPrimaryKey columnNames="CLIENT_ID, ROLE_ID" constraintName="CONSTRAINT_81" tableName="SCOPE_MAPPING"/>
<addPrimaryKey columnNames="NAME, REALM_ID" constraintName="CONSTRAINT_9" tableName="REALM_ATTRIBUTE"/>
<addPrimaryKey columnNames="REALM_ID, TYPE" constraintName="CONSTRAINT_92" tableName="REALM_REQUIRED_CREDENTIAL"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_A" tableName="KEYCLOAK_ROLE"/>
<addPrimaryKey columnNames="ROLE_ID, USER_ID" constraintName="CONSTRAINT_C" tableName="USER_ROLE_MAPPING"/>
<addPrimaryKey columnNames="REALM_ID, NAME" constraintName="CONSTRAINT_E" tableName="REALM_SMTP_CONFIG"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_F" tableName="CREDENTIAL"/>
<addPrimaryKey columnNames="USER_FEDERATION_PROVIDER_ID, NAME" constraintName="CONSTRAINT_F9" tableName="USER_FEDERATION_CONFIG"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FB" tableName="USER_ENTITY"/>
<addUniqueConstraint columnNames="ROLE_ID" constraintName="UK_8AELWNIBJI49AVXSRTUF6XJOW" tableName="APPLICATION_DEFAULT_ROLES"/>
<addUniqueConstraint columnNames="REALM_ID,NAME" constraintName="UK_B71CJLBENV945RB6GCON438AT" tableName="CLIENT"/>
<addUniqueConstraint columnNames="USERFEDERATIONPROVIDERS_ID" constraintName="UK_DCCIRJLIPU1478VQC89DID88C" tableName="FED_PROVIDERS"/>
<addUniqueConstraint columnNames="REALM_ID,EMAIL_CONSTRAINT" constraintName="UK_DYKN684SL8UP1CRFEI6ECKHD7" tableName="USER_ENTITY"/>
<addUniqueConstraint columnNames="ROLE_ID" constraintName="UK_H4WPD7W4HSOOLNI3H0SW7BTJE" tableName="REALM_DEFAULT_ROLES"/>
<addUniqueConstraint columnNames="NAME,APP_REALM_CONSTRAINT" constraintName="UK_J3RWUVD56ONTGSUHOGM184WW2" tableName="KEYCLOAK_ROLE"/>
<addUniqueConstraint columnNames="REALM_ID" constraintName="UK_L5QGA3RFME47335JY8JXYXH3I" tableName="REALM_APPLICATION"/>
<addUniqueConstraint columnNames="NAME" constraintName="UK_ORVSDMLA56612EAEFIQ6WL5OI" tableName="REALM"/>
<addUniqueConstraint columnNames="REALM_ID,USERNAME" constraintName="UK_RU8TT6T700S9V50BU18WS5HA6" tableName="USER_ENTITY"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_ROLE" constraintName="FK_11B7SGQW18I532811V7O2DV76" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="REDIRECT_URIS" constraintName="FK_1BURS8PB4OUJ97H5WUPPAHV9F" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="USER_FEDERATION_PROVIDER" constraintName="FK_1FJ32F6PTOLW2QY60CD8N01E8" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="FED_PROVIDERS" constraintName="FK_213LYQ09FKXQ8K8NY8DY3737T" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_REQUIRED_CREDENTIAL" constraintName="FK_5HG65LYBEVAVKQFKI3KPONH9V" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="USER_ATTRIBUTE" constraintName="FK_5HRM2VLF9QL5FU043KQEPOVBR" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
<addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="USER_SOCIAL_LINK" constraintName="FK_68CJYS5UWM55UY823Y75XG4OM" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
<addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="USER_REQUIRED_ACTION" constraintName="FK_6QJ3W1JW9CVAFHE19BWSIUVMD" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
<addForeignKeyConstraint baseColumnNames="REALM" baseTableName="KEYCLOAK_ROLE" constraintName="FK_6VYQFE4CN4WLQ8R6KT5VDSJ5C" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_SMTP_CONFIG" constraintName="FK_70EJ8XDXGXD0B9HH6180IRR0O" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="APPLICATION_ID" baseTableName="REALM_APPLICATION" constraintName="FK_71S3P0DIUXAWWQQSA528UBY2Q" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="ROLE_ID" baseTableName="APPLICATION_DEFAULT_ROLES" constraintName="FK_8AELWNIBJI49AVXSRTUF6XJOW" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_ATTRIBUTE" constraintName="FK_8SHXD6L3E9ATQUKACXGPFFPTW" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="COMPOSITE" baseTableName="COMPOSITE_ROLE" constraintName="FK_A63WVEKFTU8JO1PNJ81E7MCE2" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
<addForeignKeyConstraint baseColumnNames="SESSION_ID" baseTableName="CLIENT_SESSION" constraintName="FK_B4AO2VCVAT6UKAU74WBWTFQO1" referencedColumnNames="ID" referencedTableName="USER_SESSION"/>
<addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="USER_ROLE_MAPPING" constraintName="FK_C4FQV34P1MBYLLOXANG7B1Q3L" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
<addForeignKeyConstraint baseColumnNames="USERFEDERATIONPROVIDERS_ID" baseTableName="FED_PROVIDERS" constraintName="FK_DCCIRJLIPU1478VQC89DID88C" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_PROVIDER"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_DEFAULT_ROLES" constraintName="FK_EVUDB1PPW84OXFAX2DRS03ICC" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="CHILD_ROLE" baseTableName="COMPOSITE_ROLE" constraintName="FK_GR7THLLB9LU8Q4VQA4524JJY8" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
<addForeignKeyConstraint baseColumnNames="ROLE_ID" baseTableName="REALM_DEFAULT_ROLES" constraintName="FK_H4WPD7W4HSOOLNI3H0SW7BTJE" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_EVENTS_LISTENERS" constraintName="FK_H846O4H0W8EPX5NXEV9F5Y69J" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_APPLICATION" constraintName="FK_L5QGA3RFME47335JY8JXYXH3I" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="WEB_ORIGINS" constraintName="FK_LOJPHO213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="APPLICATION_ID" baseTableName="APPLICATION_DEFAULT_ROLES" constraintName="FK_MAYLTS7KLWQW2H8M2B5JOYTKY" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="SCOPE_MAPPING" constraintName="FK_OUSE064PLMLR732LXJCN1Q5F1" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="ROLE_ID" baseTableName="SCOPE_MAPPING" constraintName="FK_P3RH9GRKU11KQFRS4FLTT7RNQ" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="CLIENT" constraintName="FK_P56CTINXXB9GSK57FO49F9TAC" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="CREDENTIAL" constraintName="FK_PFYR0GLASQYL0DEI3KL69R6V0" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
<addForeignKeyConstraint baseColumnNames="APPLICATION" baseTableName="KEYCLOAK_ROLE" constraintName="FK_PIMO5LE2C0RAL09FL8CM9WFW9" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="MASTER_ADMIN_APP" baseTableName="REALM" constraintName="FK_RSAF444KK6QRKMS7N56AIWQ5Y" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_SOCIAL_CONFIG" constraintName="FK_SV5I3C2TI7G0G922FGE683SOV" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="USER_FEDERATION_PROVIDER_ID" baseTableName="USER_FEDERATION_CONFIG" constraintName="FK_T13HPU1J94R2EBPEKR39X5EU5" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_PROVIDER"/>
</changeSet>
</databaseChangeLog>
@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
<changeSet author="sthorger@redhat.com" id="1.1.0.Beta1">
<delete tableName="CLIENT_SESSION_ROLE"/>
<delete tableName="CLIENT_SESSION"/>
<delete tableName="USER_SESSION"/>
<createTable tableName="CLIENT_ATTRIBUTES">
<column name="CLIENT_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(2048)"/>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="CLIENT_SESSION_NOTE">
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="CLIENT_SESSION" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="APP_NODE_REGISTRATIONS">
<column name="APPLICATION_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="INT"/>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
<addColumn tableName="CLIENT_SESSION">
<column name="AUTH_METHOD" type="VARCHAR(255)"/>
</addColumn>
<addColumn tableName="CLIENT">
<column name="PROTOCOL" type="VARCHAR(255)"/>
</addColumn>
<addColumn tableName="CLIENT_SESSION">
<column name="REALM_ID" type="VARCHAR(255)"/>
</addColumn>
<addColumn tableName="REALM">
<column name="CERTIFICATE" type="VARCHAR(2048)"/>
<column name="CODE_SECRET" type="VARCHAR(255)"/>
</addColumn>
<addColumn tableName="CLIENT">
<column name="NODE_REREG_TIMEOUT" type="INT" defaultValueNumeric="0"/>
</addColumn>
<addPrimaryKey columnNames="CLIENT_ID, NAME" constraintName="CONSTRAINT_3C" tableName="CLIENT_ATTRIBUTES"/>
<addPrimaryKey columnNames="CLIENT_SESSION, NAME" constraintName="CONSTRAINT_5E" tableName="CLIENT_SESSION_NOTE"/>
<addPrimaryKey columnNames="APPLICATION_ID, NAME" constraintName="CONSTRAINT_84" tableName="APP_NODE_REGISTRATIONS"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="CLIENT_ATTRIBUTES" constraintName="FK3C47C64BEACCA966" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_NOTE" constraintName="FK5EDFB00FF51C2736" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
<addForeignKeyConstraint baseColumnNames="APPLICATION_ID" baseTableName="APP_NODE_REGISTRATIONS" constraintName="FK8454723BA992F594" referencedColumnNames="ID" referencedTableName="CLIENT"/>
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.AddRealmCodeSecret"/>
</changeSet>
</databaseChangeLog>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
<changeSet author="sthorger@redhat.com" id="1.1.0.Final">
<renameColumn tableName="EVENT_ENTITY" oldColumnName="TIME" newColumnName="EVENT_TIME" columnDataType="BIGINT"/>
</changeSet>
</databaseChangeLog>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
<include file="META-INF/jpa-changelog-1.0.0.Final.xml"/>
<include file="META-INF/jpa-changelog-1.1.0.Beta1.xml"/>
<include file="META-INF/jpa-changelog-1.1.0.Final.xml"/>
</databaseChangeLog>
@@ -1 +0,0 @@
org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProviderFactory
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,20 +1,12 @@
package org.keycloak.connections.jpa;
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 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;
@@ -23,15 +15,13 @@ import java.util.Map;
*/
public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory {
private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class);
private volatile EntityManagerFactory emf;
private Config.Scope config;
@Override
public JpaConnectionProvider create(KeycloakSession session) {
lazyInit(session);
lazyInit();
EntityManager em = emf.createEntityManager();
em = PersistenceExceptionConverter.create(em);
@@ -56,17 +46,11 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
this.config = config;
}
private void lazyInit(KeycloakSession session) {
private void lazyInit() {
if (emf == null) {
synchronized (this) {
if (emf == null) {
logger.debug("Initializing JPA connections");
Connection connection = null;
String unitName = config.get("unitName");
String databaseSchema = config.get("databaseSchema");
Map<String, Object> properties = new HashMap<String, Object>();
// Only load config from keycloak-server.json if unitName is not specified
@@ -99,84 +83,19 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
properties.put("hibernate.dialect", driverDialect);
}
String databaseSchema = config.get("databaseSchema", "validate");
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.hbm2ddl.auto", databaseSchema);
}
properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
}
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");
}
connection = getConnection();
if (databaseSchema.equals("update")) {
String currentVersion = null;
try {
ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql());
if (resultSet.next()) {
currentVersion = resultSet.getString(1);
}
} catch (SQLException e) {
}
if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
updater.update(connection);
} else {
logger.debug("Database is up to date");
}
} else if (databaseSchema.equals("validate")) {
updater.validate(connection);
} else {
throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
}
logger.trace("Database update completed");
}
logger.trace("Creating EntityManagerFactory");
emf = Persistence.createEntityManagerFactory(unitName, properties);
logger.trace("EntityManagerFactory created");
// Close after creating EntityManagerFactory to prevent in-mem databases from closing
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
logger.warn(e);
}
}
}
}
}
}
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);
}
}
}
@@ -1,22 +0,0 @@
package org.keycloak.connections.jpa.updater;
import org.keycloak.provider.Provider;
import java.sql.Connection;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface JpaUpdaterProvider extends Provider {
public String FIRST_VERSION = "1.0.0.Final";
public String LAST_VERSION = "1.1.0.Beta1";
public String getCurrentVersionSql();
public void update(Connection connection);
public void validate(Connection connection);
}
@@ -1,9 +0,0 @@
package org.keycloak.connections.jpa.updater;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface JpaUpdaterProviderFactory extends ProviderFactory<JpaUpdaterProvider> {
}
@@ -1,27 +0,0 @@
package org.keycloak.connections.jpa.updater;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class JpaUpdaterSpi implements Spi {
@Override
public String getName() {
return "connectionsJpaUpdater";
}
@Override
public Class<? extends Provider> getProviderClass() {
return JpaUpdaterProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return JpaUpdaterProviderFactory.class;
}
}
@@ -21,7 +21,6 @@
<!-- JpaUserSessionProvider -->
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionEntity</class>
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionRoleEntity</class>
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionNoteEntity</class>
<class>org.keycloak.models.sessions.jpa.entities.UserSessionEntity</class>
<class>org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity</class>
@@ -1,2 +1 @@
org.keycloak.connections.jpa.JpaConnectionSpi
org.keycloak.connections.jpa.updater.JpaUpdaterSpi
org.keycloak.connections.jpa.JpaConnectionSpi
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -2,7 +2,6 @@ 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 org.jboss.logging.Logger;
@@ -10,10 +9,8 @@ import org.keycloak.Config;
import org.keycloak.connections.mongo.api.MongoStore;
import org.keycloak.connections.mongo.impl.MongoStoreImpl;
import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocationContext;
import org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider;
import org.keycloak.models.KeycloakSession;
import java.lang.reflect.Method;
import java.util.Collections;
/**
@@ -67,32 +64,22 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
String host = config.get("host", ServerAddress.defaultHost());
int port = config.getInt("port", ServerAddress.defaultPort());
String dbName = config.get("db", "keycloak");
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
String user = config.get("user");
String password = config.get("password");
MongoClientOptions clientOptions = getClientOptions();
if (user != null && password != null) {
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential), clientOptions);
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
} else {
client = new MongoClient(new ServerAddress(host, port), clientOptions);
client = new MongoClient(host, port);
}
this.db = client.getDB(dbName);
String databaseSchema = config.get("databaseSchema");
if (databaseSchema != null) {
if (databaseSchema.equals("update")) {
new DefaultMongoUpdaterProvider().update(db);
} else {
throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
}
}
this.mongoStore = new MongoStoreImpl(db, clearOnStartup, getManagedEntities());
this.mongoStore = new MongoStoreImpl(db, getManagedEntities());
logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName);
logger.infof("Initialized mongo model. host: %s, port: %d, db: %s, clearOnStartup: %b", host, port, dbName, clearOnStartup);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -121,43 +108,4 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
return "default";
}
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"));
}
return builder.build();
}
protected void checkBooleanOption(String optionName, MongoClientOptions.Builder builder) {
Boolean val = config.getBoolean(optionName);
if (val != null) {
try {
Method m = MongoClientOptions.Builder.class.getMethod(optionName, boolean.class);
m.invoke(builder, val);
} catch (Exception e) {
throw new IllegalStateException("Problem configuring boolean option " + optionName + " for mongo client. Ensure you used correct value true or false and if this option is supported by mongo driver", e);
}
}
}
protected void checkIntOption(String optionName, MongoClientOptions.Builder builder) {
Integer val = config.getInt(optionName);
if (val != null) {
try {
Method m = MongoClientOptions.Builder.class.getMethod(optionName, int.class);
m.invoke(builder, val);
} catch (Exception e) {
throw new IllegalStateException("Problem configuring int option " + optionName + " for mongo client. Ensure you used correct value (number) and if this option is supported by mongo driver", e);
}
}
}
}
@@ -0,0 +1,26 @@
package org.keycloak.connections.mongo.api;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@Target({TYPE})
@Documented
@Retention(RUNTIME)
@Inherited
public @interface MongoIndex {
String[] fields();
boolean unique() default false;
boolean sparse() default false;
}
@@ -0,0 +1,22 @@
package org.keycloak.connections.mongo.api;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@Target({TYPE})
@Documented
@Retention(RUNTIME)
@Inherited
public @interface MongoIndexes {
MongoIndex[] value();
}
@@ -11,6 +11,8 @@ import org.jboss.logging.Logger;
import org.keycloak.connections.mongo.api.MongoCollection;
import org.keycloak.connections.mongo.api.MongoEntity;
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
import org.keycloak.connections.mongo.api.MongoIndex;
import org.keycloak.connections.mongo.api.MongoIndexes;
import org.keycloak.connections.mongo.api.MongoStore;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.connections.mongo.api.context.MongoTask;
@@ -55,7 +57,7 @@ public class MongoStoreImpl implements MongoStore {
new ConcurrentHashMap<Class<?>, EntityInfo>();
public MongoStoreImpl(DB database, Class<?>[] managedEntityTypes) {
public MongoStoreImpl(DB database, boolean clearCollectionsOnStartup, Class<?>[] managedEntityTypes) {
this.database = database;
mapperRegistry = new MapperRegistry();
@@ -84,6 +86,13 @@ public class MongoStoreImpl implements MongoStore {
mapperRegistry.addAppObjectMapper(new MongoEntityMapper(this, mapperRegistry, type));
mapperRegistry.addDBObjectMapper(new BasicDBObjectMapper(this, mapperRegistry, type));
}
if (clearCollectionsOnStartup) {
// dropDatabase();
clearManagedCollections(managedEntityTypes);
}
initManagedCollections(managedEntityTypes);
}
protected void dropDatabase() {
@@ -91,6 +100,63 @@ public class MongoStoreImpl implements MongoStore {
logger.info("Database " + this.database.getName() + " dropped in MongoDB");
}
// Don't drop database, but just clear all data in managed collections (useful for export/import or during development)
protected void clearManagedCollections(Class<?>[] managedEntityTypes) {
for (Class<?> clazz : managedEntityTypes) {
DBCollection dbCollection = getDBCollectionForType(clazz);
if (dbCollection != null) {
dbCollection.remove(new BasicDBObject());
logger.debug("Collection " + dbCollection.getName() + " cleared from " + this.database.getName());
}
}
}
protected void initManagedCollections(Class<?>[] managedEntityTypes) {
for (Class<?> clazz : managedEntityTypes) {
EntityInfo entityInfo = getEntityInfo(clazz);
String dbCollectionName = entityInfo.getDbCollectionName();
if (dbCollectionName != null && !database.collectionExists(dbCollectionName)) {
DBCollection dbCollection = database.getCollection(dbCollectionName);
logger.debug("Created collection " + dbCollection.getName() + " in " + this.database.getName());
MongoIndex index = clazz.getAnnotation(MongoIndex.class);
if (index != null) {
createIndex(dbCollection, index);
}
MongoIndexes indexes = clazz.getAnnotation(MongoIndexes.class);
if (indexes != null) {
for (MongoIndex i : indexes.value()) {
createIndex(dbCollection, i);
}
}
}
}
}
protected void createIndex(DBCollection dbCollection, MongoIndex index) {
BasicDBObject fields = new BasicDBObject();
for (String f : index.fields()) {
fields.put(f, 1);
}
boolean unique = index.unique();
boolean sparse = index.sparse();
BasicDBObject options = new BasicDBObject();
if (unique) {
options.put("unique", unique);
}
if (sparse) {
options.put("sparse", sparse);
}
dbCollection.ensureIndex(fields, options);
logger.debug("Created index " + fields + "(options: " + options + ") on " + dbCollection.getName() + " in " + this.database.getName());
}
@Override
public void insertEntity(MongoIdentifiableEntity entity, MongoStoreInvocationContext context) {
Class<? extends MongoEntity> clazz = entity.getClass();
@@ -259,7 +325,7 @@ public class MongoStoreImpl implements MongoStore {
DBCollection dbCollection = getDBCollectionForType(type);
BasicDBObject dbQuery = new BasicDBObject("_id", id);
dbCollection.remove(dbQuery);
//logger.debugf("Entity of type: %s , id: %s removed from MongoDB.", type, id);
logger.info("Entity of type: " + type + ", id: " + id + " removed from MongoDB.");
context.addRemovedEntity(found);
return true;
@@ -275,7 +341,7 @@ public class MongoStoreImpl implements MongoStore {
} else {
DBCollection dbCollection = getDBCollectionForType(type);
dbCollection.remove(query);
//logger.debug("Removed %d" + foundObjects.size() + " entities of type: " + type + ", query: " + query);
logger.info("Removed " + foundObjects.size() + " entities of type: " + type + ", query: " + query);
for (MongoIdentifiableEntity found : foundObjects) {
context.addRemovedEntity(found);;
@@ -9,7 +9,7 @@ import org.keycloak.connections.mongo.api.types.MapperRegistry;
import org.keycloak.connections.mongo.impl.EntityInfo;
import org.keycloak.connections.mongo.impl.MongoStoreImpl;
import org.keycloak.models.utils.reflection.Property;
import org.keycloak.util.reflections.Types;
import org.keycloak.models.utils.reflection.Types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -8,7 +8,7 @@ import java.util.HashMap;
import java.util.Map;
/**
* For now, there is support just for convert to Map<String, simpleType>
* For now, there is support just for convert to Map<String, String>
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -18,15 +18,10 @@ public class BasicDBObjectToMapMapper implements Mapper<BasicDBObject, Map> {
public Map convertObject(MapperContext<BasicDBObject, Map> context) {
BasicDBObject dbObjectToConvert = context.getObjectToConvert();
HashMap<String, Object> result = new HashMap<String, Object>();
HashMap<String, String> result = new HashMap<String, String>();
for (Map.Entry<String, Object> entry : dbObjectToConvert.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// Workaround as manually inserted numbers into mongo may be treated as "Double"
if (value instanceof Double && context.getGenericTypes().get(1) == Integer.class) {
value = ((Double)value).intValue();
}
String value = (String)entry.getValue();
if (key.contains(MapMapper.DOT_PLACEHOLDER)) {
key = key.replaceAll(MapMapper.DOT_PLACEHOLDER, ".");
@@ -8,7 +8,7 @@ import java.util.Map;
import java.util.Set;
/**
* For now, we support just convert from Map<String, simpleType>
* For now, we support just convert from Map<String, String>
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -31,7 +31,7 @@ public class MapMapper<T extends Map> implements Mapper<T, BasicDBObject> {
Set<Map.Entry> entries = objectToConvert.entrySet();
for (Map.Entry entry : entries) {
String key = (String)entry.getKey();
Object value = entry.getValue();
String value = (String)entry.getValue();
if (key.contains(".")) {
key = key.replaceAll("\\.", DOT_PLACEHOLDER);
@@ -1,103 +0,0 @@
package org.keycloak.connections.mongo.updater;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import org.jboss.logging.Logger;
import org.keycloak.connections.mongo.updater.updates.Update;
import org.keycloak.connections.mongo.updater.updates.Update1_0_0_Final;
import org.keycloak.connections.mongo.updater.updates.Update1_1_0_Beta1;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
public static final Logger log = Logger.getLogger(DefaultMongoUpdaterProvider.class);
public static final String CHANGE_LOG_COLLECTION = "databaseChangeLog";
private Class<? extends Update>[] updates = new Class[]{
Update1_0_0_Final.class,
Update1_1_0_Beta1.class
};
@Override
public void update(DB db) {
log.debug("Starting database update");
try {
boolean changeLogExists = db.collectionExists(CHANGE_LOG_COLLECTION);
boolean realmExists = db.collectionExists("realms");
DBCollection changeLog = db.getCollection(CHANGE_LOG_COLLECTION);
List<String> executed = new LinkedList<String>();
if (!changeLogExists && realmExists) {
Update1_0_0_Final u = new Update1_0_0_Final();
executed.add(u.getId());
createLog(changeLog, u, 1);
} else if (changeLogExists) {
DBCursor cursor = changeLog.find().sort(new BasicDBObject("orderExecuted", 1));
while (cursor.hasNext()) {
executed.add((String) cursor.next().get("_id"));
}
}
List<Update> updatesToRun = new LinkedList<Update>();
for (Class<? extends Update> updateClass : updates) {
Update u = updateClass.newInstance();
if (!executed.contains(u.getId())) {
updatesToRun.add(u);
}
}
if (!updatesToRun.isEmpty()) {
if (executed.isEmpty()) {
log.info("Initializing database schema");
} else {
if (log.isDebugEnabled()) {
log.infov("Updating database from {0} to {1}", executed.get(executed.size() - 1), updatesToRun.get(updatesToRun.size() - 1).getId());
} else {
log.debugv("Updating database");
}
}
int order = executed.size();
for (Update u : updatesToRun) {
log.debugv("Executing updates for {0}", u.getId());
u.setLog(log);
u.setDb(db);
u.update();
createLog(changeLog, u, ++order);
log.debugv("Completed updates for {0}", u.getId());
}
}
} catch (Exception e) {
throw new RuntimeException("Failed to update database", e);
}
log.debug("Completed database update");
}
private void createLog(DBCollection changeLog, Update update, int orderExecuted) {
changeLog.insert(new BasicDBObject("_id", update.getId()).append("dateExecuted", new Date()).append("orderExecuted", orderExecuted));
}
@Override
public void close() {
}
}
@@ -1,29 +0,0 @@
package org.keycloak.connections.mongo.updater;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class DefaultMongoUpdaterProviderFactory implements MongoUpdaterProviderFactory {
@Override
public MongoUpdaterProvider create(KeycloakSession session) {
return new DefaultMongoUpdaterProvider();
}
@Override
public void init(Config.Scope config) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "default";
}
}
@@ -1,13 +0,0 @@
package org.keycloak.connections.mongo.updater;
import com.mongodb.DB;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface MongoUpdaterProvider extends Provider {
public void update(DB db);
}
@@ -1,9 +0,0 @@
package org.keycloak.connections.mongo.updater;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface MongoUpdaterProviderFactory extends ProviderFactory<MongoUpdaterProvider> {
}
@@ -1,27 +0,0 @@
package org.keycloak.connections.mongo.updater;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class MongoUpdaterSpi implements Spi {
@Override
public String getName() {
return "connectionsMongoUpdater";
}
@Override
public Class<? extends Provider> getProviderClass() {
return MongoUpdaterProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return MongoUpdaterProviderFactory.class;
}
}
@@ -1,62 +0,0 @@
package org.keycloak.connections.mongo.updater.updates;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import org.jboss.logging.Logger;
import java.util.Arrays;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public abstract class Update {
protected DB db;
protected Logger log;
public abstract String getId();
public abstract void update() throws ClassNotFoundException;
protected DBCollection createCollection(String name) {
if (db.collectionExists(name)) {
throw new RuntimeException("Failed to create collection {0}: collection already exists");
}
DBCollection col = db.getCollection(name);
log.debugv("Created collection {0}", name);
return col;
}
protected void ensureIndex(String name, String field, boolean unique, boolean sparse) {
ensureIndex(name, new String[]{field}, unique, sparse);
}
protected void ensureIndex(String name, String[] fields, boolean unique, boolean sparse) {
DBCollection col = db.getCollection(name);
BasicDBObject o = new BasicDBObject();
for (String f : fields) {
o.append(f, 1);
}
col.ensureIndex(o, new BasicDBObject("unique", unique).append("sparse", sparse));
log.debugv("Created index {0}, fields={1}, unique={2}, sparse={3}", name, Arrays.toString(fields), unique, sparse);
}
protected void deleteEntries(String collection) {
db.getCollection(collection).remove(new BasicDBObject());
log.debugv("Deleted entries from {0}", collection);
}
public void setLog(Logger log) {
this.log = log;
}
public void setDb(DB db) {
this.db = db;
}
}
@@ -1,44 +0,0 @@
package org.keycloak.connections.mongo.updater.updates;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class Update1_0_0_Final extends Update {
@Override
public String getId() {
return "1.0.0.Final";
}
@Override
public void update() throws ClassNotFoundException {
DBCollection realmsCollection = db.getCollection("realms");
realmsCollection.ensureIndex(new BasicDBObject("name", 1), new BasicDBObject("unique", true));
DefaultMongoUpdaterProvider.log.debugv("Created collection {0}", "realms");
createCollection("users");
ensureIndex("users", new String[] { "realmId", "username"}, true, false);
ensureIndex("users", "emailIndex", true, true);
createCollection("roles");
ensureIndex("roles", "nameIndex", true, false);
createCollection("applications");
ensureIndex("applications", new String[]{"realmId", "name"}, true, false);
createCollection("oauthClients");
ensureIndex("oauthClients", new String[] { "realmId", "name"}, true, false);
createCollection("userFailures");
createCollection("sessions");
createCollection("clientSessions");
}
}
@@ -1,45 +0,0 @@
package org.keycloak.connections.mongo.updater.updates;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.Arrays;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class Update1_1_0_Beta1 extends Update {
@Override
public String getId() {
return "1.1.0.Beta1";
}
@Override
public void update() {
deleteEntries("clientSessions");
deleteEntries("sessions");
addRealmCodeSecret();
}
private void addRealmCodeSecret() {
DBCollection realms = db.getCollection("realms");
DBObject query = new QueryBuilder()
.and("codeSecret").is(null).get();
DBCursor objects = realms.find(query);
while (objects.hasNext()) {
DBObject object = objects.next();
object.put("codeSecret", KeycloakModelUtils.generateCodeSecret());
realms.save(object);
log.debugv("Added realm.codeSecret, id={0}", object.get("id"));
}
}
}
+1 -3
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
</parent>
<name>Connections Parent</name>
<description/>
@@ -14,8 +14,6 @@
<modules>
<module>jpa</module>
<module>jpa-liquibase</module>
<module>infinispan</module>
<module>mongo</module>
</modules>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -31,7 +31,7 @@ public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper>
@Override
public ObjectMapper getContext(Class<?> type) {
if (type.getPackage() != null && type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper;
if (type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper;
return null;
}
}
+1 -42
View File
@@ -4,26 +4,18 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-core</artifactId>
<name>Keycloak Core</name>
<packaging>jar</packaging>
<description/>
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
<keycloak.osgi.export>
org.keycloak.*
</keycloak.osgi.export>
<keycloak.osgi.import>
net.iharder;version=${base64.version},
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<dependencies>
<dependency>
@@ -68,39 +60,6 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-ClassPath>.</Bundle-ClassPath>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
@@ -1,6 +1,5 @@
package org.keycloak;
import org.keycloak.enums.RelativeUrlsUsed;
import org.keycloak.util.KeycloakUriBuilder;
import java.util.Map;
@@ -20,7 +19,7 @@ public class AbstractOAuthClient {
protected String authUrl;
protected String codeUrl;
protected String refreshUrl;
protected RelativeUrlsUsed relativeUrlsUsed;
protected boolean relativeUrls;
protected String scope;
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
protected String stateCookiePath;
@@ -102,12 +101,12 @@ public class AbstractOAuthClient {
this.publicClient = publicClient;
}
public RelativeUrlsUsed getRelativeUrlsUsed() {
return relativeUrlsUsed;
public boolean isRelativeUrls() {
return relativeUrls;
}
public void setRelativeUrlsUsed(RelativeUrlsUsed relativeUrlsUsed) {
this.relativeUrlsUsed = relativeUrlsUsed;
public void setRelativeUrls(boolean relativeUrls) {
this.relativeUrls = relativeUrls;
}
protected String stripOauthParametersFromRedirect(String uri) {
@@ -121,17 +121,6 @@ public class Config {
return v != null ? Boolean.parseBoolean(v) : defaultValue;
}
@Override
public Scope scope(String... scope) {
StringBuilder sb = new StringBuilder();
sb.append(prefix + ".");
for (String s : scope) {
sb.append(s);
sb.append(".");
}
return new SystemPropertiesScope(sb.toString());
}
}
/**
@@ -157,7 +146,5 @@ public class Config {
Boolean getBoolean(String key, Boolean defaultValue);
Scope scope(String... scope);
}
}
@@ -7,16 +7,16 @@ import java.security.Principal;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakPrincipal<T extends KeycloakSecurityContext> implements Principal, Serializable {
public class KeycloakPrincipal implements Principal, Serializable {
protected final String name;
protected final T context;
protected final KeycloakSecurityContext context;
public KeycloakPrincipal(String name, T context) {
public KeycloakPrincipal(String name, KeycloakSecurityContext context) {
this.name = name;
this.context = context;
}
public T getKeycloakSecurityContext() {
public KeycloakSecurityContext getKeycloakSecurityContext() {
return context;
}
@@ -2,12 +2,7 @@ package org.keycloak;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.util.Base64Url;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
@@ -16,12 +11,10 @@ import java.io.Serializable;
*/
public class KeycloakSecurityContext implements Serializable {
protected String tokenString;
protected AccessToken token;
protected IDToken idToken;
protected String idTokenString;
// Don't store parsed tokens into HTTP session
protected transient AccessToken token;
protected transient IDToken idToken;
public KeycloakSecurityContext() {
}
@@ -47,36 +40,4 @@ public class KeycloakSecurityContext implements Serializable {
public String getIdTokenString() {
return idTokenString;
}
public String getRealm() {
// Assumption that issuer contains realm name
return token.getIssuer();
}
// SERIALIZATION
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
token = parseToken(tokenString, AccessToken.class);
idToken = parseToken(idTokenString, IDToken.class);
}
// Just decode token without any verifications
private <T> T parseToken(String encoded, Class<T> clazz) throws IOException {
if (encoded == null)
return null;
String[] parts = encoded.split("\\.");
if (parts.length < 2 || parts.length > 3) throw new IllegalArgumentException("Parsing error");
byte[] bytes = Base64Url.decode(parts[1]);
return JsonSerialization.readValue(bytes, clazz);
}
}
@@ -35,7 +35,7 @@ public class RSATokenVerifier {
if (user == null) {
throw new VerificationException("Token user was null.");
}
if (!realm.equals(token.getIssuer())) {
if (!realm.equals(token.getAudience())) {
throw new VerificationException("Token audience doesn't match domain.");
}
@@ -1,4 +1,4 @@
package org.keycloak.constants;
package org.keycloak;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -6,14 +6,12 @@ package org.keycloak.constants;
*/
public interface ServiceUrlConstants {
public static final String TOKEN_SERVICE_LOGIN_PATH = "/realms/{realm-name}/protocol/openid-connect/login";
public static final String TOKEN_SERVICE_ACCESS_CODE_PATH = "/realms/{realm-name}/protocol/openid-connect/access/codes";
public static final String TOKEN_SERVICE_REFRESH_PATH = "/realms/{realm-name}/protocol/openid-connect/refresh";
public static final String TOKEN_SERVICE_LOGOUT_PATH = "/realms/{realm-name}/protocol/openid-connect/logout";
public static final String TOKEN_SERVICE_DIRECT_GRANT_PATH = "/realms/{realm-name}/protocol/openid-connect/grants/access";
public static final String TOKEN_SERVICE_LOGIN_PATH = "/realms/{realm-name}/tokens/login";
public static final String TOKEN_SERVICE_ACCESS_CODE_PATH = "/realms/{realm-name}/tokens/access/codes";
public static final String TOKEN_SERVICE_REFRESH_PATH = "/realms/{realm-name}/tokens/refresh";
public static final String TOKEN_SERVICE_LOGOUT_PATH = "/realms/{realm-name}/tokens/logout";
public static final String TOKEN_SERVICE_DIRECT_GRANT_PATH = "/realms/{realm-name}/tokens/grants/access";
public static final String ACCOUNT_SERVICE_PATH = "/realms/{realm-name}/account";
public static final String REALM_INFO_PATH = "/realms/{realm-name}";
public static final String CLIENTS_MANAGEMENT_REGISTER_NODE_PATH = "/realms/{realm-name}/clients-managements/register-node";
public static final String CLIENTS_MANAGEMENT_UNREGISTER_NODE_PATH = "/realms/{realm-name}/clients-managements/unregister-node";
}
@@ -0,0 +1,21 @@
package org.keycloak.adapters;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AdapterConstants {
// URL endpoints
public static final String K_LOGOUT = "k_logout";
public static final String K_VERSION = "k_version";
public static final String K_PUSH_NOT_BEFORE = "k_push_not_before";
public static final String K_GET_USER_STATS = "k_get_user_stats";
public static final String K_GET_SESSION_STATS = "k_get_session_stats";
public static final String K_QUERY_BEARER_TOKEN = "k_query_bearer_token";
// This param name is defined again in Keycloak Subsystem class
// org.keycloak.subsystem.extensionKeycloakAdapterConfigDeploymentProcessor. We have this value in
// two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
}
@@ -1,32 +0,0 @@
package org.keycloak.constants;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AdapterConstants {
// URL endpoints
public static final String K_LOGOUT = "k_logout";
public static final String K_VERSION = "k_version";
public static final String K_PUSH_NOT_BEFORE = "k_push_not_before";
public static final String K_TEST_AVAILABLE = "k_test_available";
public static final String K_QUERY_BEARER_TOKEN = "k_query_bearer_token";
// This param name is defined again in Keycloak Subsystem class
// org.keycloak.subsystem.extensionKeycloakAdapterConfigDeploymentProcessor. We have this value in
// two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
// Attribute passed in codeToToken request from adapter to Keycloak and saved in ClientSession. Contains ID of HttpSession on adapter
public static final String APPLICATION_SESSION_STATE = "application_session_state";
// Attribute passed in codeToToken request from adapter to Keycloak and saved in ClientSession. Contains hostname of adapter where HttpSession is served
public static final String APPLICATION_SESSION_HOST = "application_session_host";
// Attribute passed in registerNode request for register new application cluster node once he joined cluster
public static final String APPLICATION_CLUSTER_HOST = "application_cluster_host";
// Cookie used on adapter side to store token info. Used only when tokenStore is 'COOKIE'
public static final String KEYCLOAK_ADAPTER_STATE_COOKIE = "KEYCLOAK_ADAPTER_STATE";
}
@@ -1,10 +0,0 @@
package org.keycloak.constants;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class GenericConstants {
public static final String PROTOCOL_CLASSPATH = "classpath:";
}
@@ -1,36 +0,0 @@
package org.keycloak.enums;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public enum RelativeUrlsUsed {
/**
* Always use relative URI and resolve them later based on browser HTTP request
*/
ALL_REQUESTS,
/**
* Use relative Uris just for browser requests and resolve those based on browser HTTP requests.
* Backend request (like refresh token request, codeToToken request etc) will use the URI based on current hostname
*/
BROWSER_ONLY,
/**
* Relative Uri not used. Configuration contains absolute URI
*/
NEVER;
public boolean useRelative(boolean isBrowserReq) {
switch (this) {
case ALL_REQUESTS:
return true;
case NEVER:
return false;
case BROWSER_ONLY:
return isBrowserReq;
default:
return true;
}
}
}
@@ -1,9 +0,0 @@
package org.keycloak.enums;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public enum TokenStore {
SESSION,
COOKIE
}
@@ -58,18 +58,16 @@ public class JWSBuilder {
}
}
protected String encodeAll(StringBuffer encoding, byte[] signature) {
encoding.append('.');
if (signature != null) {
encoding.append(Base64Url.encode(signature));
}
return encoding.toString();
}
protected void encode(Algorithm alg, byte[] data, StringBuffer encoding) {
protected String encode(Algorithm alg, byte[] data, byte[] signature) {
StringBuffer encoding = new StringBuffer();
encoding.append(encodeHeader(alg));
encoding.append('.');
encoding.append(Base64Url.encode(data));
encoding.append('.');
if (alg != Algorithm.none) {
encoding.append(Base64Url.encode(signature));
}
return encoding.toString();
}
protected byte[] marshalContent() {
@@ -78,128 +76,63 @@ public class JWSBuilder {
public class EncodingBuilder {
public String none() {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.none, data, buffer);
return encodeAll(buffer, null);
return encode(Algorithm.none, data, null);
}
public String rsa256(PrivateKey privateKey) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.RS256, data, buffer);
byte[] signature = null;
try {
signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.RS256, privateKey);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = RSAProvider.sign(data, Algorithm.RS256, privateKey);
return encode(Algorithm.RS256, data, signature);
}
public String rsa384(PrivateKey privateKey) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.RS384, data, buffer);
byte[] signature = null;
try {
signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.RS384, privateKey);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = RSAProvider.sign(data, Algorithm.RS384, privateKey);
return encode(Algorithm.RS384, data, signature);
}
public String rsa512(PrivateKey privateKey) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.RS512, data, buffer);
byte[] signature = null;
try {
signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.RS512, privateKey);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = RSAProvider.sign(data, Algorithm.RS512, privateKey);
return encode(Algorithm.RS512, data, signature);
}
public String hmac256(byte[] sharedSecret) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.HS256, data, buffer);
byte[] signature = null;
try {
signature = HMACProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.HS256, sharedSecret);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = HMACProvider.sign(data, Algorithm.HS256, sharedSecret);
return encode(Algorithm.HS256, data, signature);
}
public String hmac384(byte[] sharedSecret) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.HS384, data, buffer);
byte[] signature = null;
try {
signature = HMACProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.HS384, sharedSecret);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = HMACProvider.sign(data, Algorithm.HS384, sharedSecret);
return encode(Algorithm.HS384, data, signature);
}
public String hmac512(byte[] sharedSecret) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.HS512, data, buffer);
byte[] signature = null;
try {
signature = HMACProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.HS512, sharedSecret);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = HMACProvider.sign(data, Algorithm.HS512, sharedSecret);
return encode(Algorithm.HS512, data, signature);
}
public String hmac256(SecretKey sharedSecret) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.HS256, data, buffer);
byte[] signature = null;
try {
signature = HMACProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.HS256, sharedSecret);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = HMACProvider.sign(data, Algorithm.HS256, sharedSecret);
return encode(Algorithm.HS256, data, signature);
}
public String hmac384(SecretKey sharedSecret) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.HS384, data, buffer);
byte[] signature = null;
try {
signature = HMACProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.HS384, sharedSecret);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = HMACProvider.sign(data, Algorithm.HS384, sharedSecret);
return encode(Algorithm.HS384, data, signature);
}
public String hmac512(SecretKey sharedSecret) {
StringBuffer buffer = new StringBuffer();
byte[] data = marshalContent();
encode(Algorithm.HS512, data, buffer);
byte[] signature = null;
try {
signature = HMACProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.HS512, sharedSecret);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return encodeAll(buffer, signature);
byte[] signature = HMACProvider.sign(data, Algorithm.HS512, sharedSecret);
return encode(Algorithm.HS512, data, signature);
}
}
}
@@ -15,7 +15,6 @@ public class JWSInput {
String encodedHeader;
String encodedContent;
String encodedSignature;
String encodedSignatureInput;
JWSHeader header;
byte[] content;
byte[] signature;
@@ -27,7 +26,6 @@ public class JWSInput {
if (parts.length < 2 || parts.length > 3) throw new IllegalArgumentException("Parsing error");
encodedHeader = parts[0];
encodedContent = parts[1];
encodedSignatureInput = encodedHeader + '.' + encodedContent;
try {
content = Base64Url.decode(encodedContent);
if (parts.length > 2) {
@@ -57,9 +55,6 @@ public class JWSInput {
public String getEncodedSignature() {
return encodedSignature;
}
public String getEncodedSignatureInput() {
return encodedSignatureInput;
}
public JWSHeader getHeader() {
return header;
@@ -74,7 +74,7 @@ public class HMACProvider {
public static boolean verify(JWSInput input, byte[] sharedSecret) {
try {
byte[] signature = sign(input.getEncodedSignatureInput().getBytes("UTF-8"), input.getHeader().getAlgorithm(), sharedSecret);
byte[] signature = sign(input.getContent(), input.getHeader().getAlgorithm(), sharedSecret);
String x = Base64Url.encode(signature);
return x.equals(input.getEncodedSignature());
} catch (Exception e) {
@@ -49,7 +49,7 @@ public class RSAProvider {
try {
Signature verifier = getSignature(input.getHeader().getAlgorithm());
verifier.initVerify(publicKey);
verifier.update(input.getEncodedSignatureInput().getBytes("UTF-8"));
verifier.update(input.getContent());
return verifier.verify(input.getSignature());
} catch (Exception e) {
throw new RuntimeException(e);
@@ -3,7 +3,6 @@ package org.keycloak.representations;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -14,7 +13,7 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class AccessToken extends IDToken {
public static class Access implements Serializable {
public static class Access {
@JsonProperty("roles")
protected Set<String> roles;
@JsonProperty("verify_caller")
@@ -15,9 +15,6 @@ public class AccessTokenResponse {
@JsonProperty("expires_in")
protected long expiresIn;
@JsonProperty("refresh_expires_in")
protected long refreshExpiresIn;
@JsonProperty("refresh_token")
protected String refreshToken;
@@ -49,14 +46,6 @@ public class AccessTokenResponse {
this.expiresIn = expiresIn;
}
public long getRefreshExpiresIn() {
return refreshExpiresIn;
}
public void setRefreshExpiresIn(long refreshExpiresIn) {
this.refreshExpiresIn = refreshExpiresIn;
}
public String getRefreshToken() {
return refreshToken;
}
@@ -1,60 +0,0 @@
package org.keycloak.representations.adapters.action;
import java.util.ArrayList;
import java.util.List;
/**
* Result of the "global" request (like push notBefore or logoutAll), which is send to all cluster nodes
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class GlobalRequestResult {
private List<String> successRequests;
private List<String> failedRequests;
public void addSuccessRequest(String reqUri) {
if (successRequests == null) {
successRequests = new ArrayList<String>();
}
successRequests.add(reqUri);
}
public void addFailedRequest(String reqUri) {
if (failedRequests == null) {
failedRequests = new ArrayList<String>();
}
failedRequests.add(reqUri);
}
public void addAllSuccessRequests(List<String> reqUris) {
if (successRequests == null) {
successRequests = new ArrayList<String>();
}
successRequests.addAll(reqUris);
}
public void addAllFailedRequests(List<String> reqUris) {
if (failedRequests == null) {
failedRequests = new ArrayList<String>();
}
failedRequests.addAll(reqUris);
}
public void addAll(GlobalRequestResult merged) {
if (merged.getSuccessRequests() != null && merged.getSuccessRequests().size() > 0) {
addAllSuccessRequests(merged.getSuccessRequests());
}
if (merged.getFailedRequests() != null && merged.getFailedRequests().size() > 0) {
addAllFailedRequests(merged.getFailedRequests());
}
}
public List<String> getSuccessRequests() {
return successRequests;
}
public List<String> getFailedRequests() {
return failedRequests;
}
}
@@ -1,25 +1,40 @@
package org.keycloak.representations.adapters.action;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class LogoutAction extends AdminAction {
public static final String LOGOUT = "LOGOUT";
protected List<String> adapterSessionIds;
protected String user;
private String session;
protected int notBefore;
public LogoutAction() {
}
public LogoutAction(String id, int expiration, String resource, List<String> adapterSessionIds, int notBefore) {
public LogoutAction(String id, int expiration, String resource, String user, String session, int notBefore) {
super(id, expiration, resource, LOGOUT);
this.adapterSessionIds = adapterSessionIds;
this.user = user;
this.session = session;
this.notBefore = notBefore;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
public int getNotBefore() {
return notBefore;
@@ -29,10 +44,6 @@ public class LogoutAction extends AdminAction {
this.notBefore = notBefore;
}
public List<String> getAdapterSessionIds() {
return adapterSessionIds;
}
@Override
public boolean validate() {
return LOGOUT.equals(action);
@@ -0,0 +1,37 @@
package org.keycloak.representations.adapters.action;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SessionStats {
protected int activeSessions;
protected int activeUsers;
protected Map<String, UserStats> users;
public int getActiveSessions() {
return activeSessions;
}
public void setActiveSessions(int activeSessions) {
this.activeSessions = activeSessions;
}
public int getActiveUsers() {
return activeUsers;
}
public void setActiveUsers(int activeUsers) {
this.activeUsers = activeUsers;
}
public Map<String, UserStats> getUsers() {
return users;
}
public void setUsers(Map<String, UserStats> users) {
this.users = users;
}
}
@@ -0,0 +1,35 @@
package org.keycloak.representations.adapters.action;
/**
* Query session stats.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SessionStatsAction extends AdminAction {
public static final String SESSION_STATS = "SESSION_STATS";
protected boolean listUsers;
public SessionStatsAction() {
}
public SessionStatsAction(String id, int expiration, String resource) {
super(id, expiration, resource, SESSION_STATS);
}
public boolean isListUsers() {
return listUsers;
}
public void setListUsers(boolean listUsers) {
this.listUsers = listUsers;
}
@Override
public boolean validate() {
return SESSION_STATS.equals(action);
}
}
@@ -1,22 +0,0 @@
package org.keycloak.representations.adapters.action;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class TestAvailabilityAction extends AdminAction {
public static final String TEST_AVAILABILITY = "TEST_AVAILABILITY";
public TestAvailabilityAction() {
}
public TestAvailabilityAction(String id, int expiration, String resource) {
super(id, expiration, resource, TEST_AVAILABILITY);
}
@Override
public boolean validate() {
return TEST_AVAILABILITY.equals(action);
}
}
@@ -0,0 +1,26 @@
package org.keycloak.representations.adapters.action;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserStats {
protected boolean loggedIn;
protected long whenLoggedIn;
public boolean isLoggedIn() {
return loggedIn;
}
public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}
public long getWhenLoggedIn() {
return whenLoggedIn;
}
public void setWhenLoggedIn(long whenLoggedIn) {
this.whenLoggedIn = whenLoggedIn;
}
}
@@ -0,0 +1,31 @@
package org.keycloak.representations.adapters.action;
/**
* Query session stats.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserStatsAction extends AdminAction {
public static final String USER_STATS = "USER_STATS";
protected String user;
public UserStatsAction() {
}
public UserStatsAction(String id, int expiration, String resource, String user) {
super(id, expiration, resource, USER_STATS);
this.user = user;
}
public String getUser() {
return user;
}
@Override
public boolean validate() {
return USER_STATS.equals(action);
}
}
@@ -10,15 +10,13 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
* @version $Revision: 1 $
*/
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
"resource", "public-client", "credentials",
"resource", "credentials",
"use-resource-role-mappings",
"enable-cors", "cors-max-age", "cors-allowed-methods",
"expose-token", "bearer-only",
"connection-pool-size",
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
"client-keystore", "client-keystore-password", "client-key-password",
"auth-server-url-for-backend-requests", "always-refresh-token",
"register-node-at-startup", "register-node-period", "token-store", "principal-attribute"
"client-keystore", "client-keystore-password", "client-key-password"
})
public class AdapterConfig extends BaseAdapterConfig {
@@ -38,18 +36,6 @@ public class AdapterConfig extends BaseAdapterConfig {
protected String clientKeyPassword;
@JsonProperty("connection-pool-size")
protected int connectionPoolSize = 20;
@JsonProperty("auth-server-url-for-backend-requests")
protected String authServerUrlForBackendRequests;
@JsonProperty("always-refresh-token")
protected boolean alwaysRefreshToken = false;
@JsonProperty("register-node-at-startup")
protected boolean registerNodeAtStartup = false;
@JsonProperty("register-node-period")
protected int registerNodePeriod = -1;
@JsonProperty("token-store")
protected String tokenStore;
@JsonProperty("principal-attribute")
protected String principalAttribute;
public boolean isAllowAnyHostname() {
return allowAnyHostname;
@@ -115,51 +101,4 @@ public class AdapterConfig extends BaseAdapterConfig {
this.connectionPoolSize = connectionPoolSize;
}
public String getAuthServerUrlForBackendRequests() {
return authServerUrlForBackendRequests;
}
public void setAuthServerUrlForBackendRequests(String authServerUrlForBackendRequests) {
this.authServerUrlForBackendRequests = authServerUrlForBackendRequests;
}
public boolean isAlwaysRefreshToken() {
return alwaysRefreshToken;
}
public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
this.alwaysRefreshToken = alwaysRefreshToken;
}
public boolean isRegisterNodeAtStartup() {
return registerNodeAtStartup;
}
public void setRegisterNodeAtStartup(boolean registerNodeAtStartup) {
this.registerNodeAtStartup = registerNodeAtStartup;
}
public int getRegisterNodePeriod() {
return registerNodePeriod;
}
public void setRegisterNodePeriod(int registerNodePeriod) {
this.registerNodePeriod = registerNodePeriod;
}
public String getTokenStore() {
return tokenStore;
}
public void setTokenStore(String tokenStore) {
this.tokenStore = tokenStore;
}
public String getPrincipalAttribute() {
return principalAttribute;
}
public void setPrincipalAttribute(String principalAttribute) {
this.principalAttribute = principalAttribute;
}
}
@@ -16,7 +16,7 @@ import java.util.Map;
"resource", "public-client", "credentials",
"use-resource-role-mappings",
"enable-cors", "cors-max-age", "cors-allowed-methods",
"expose-token", "bearer-only", "enable-basic-auth"})
"expose-token", "bearer-only"})
public class BaseAdapterConfig extends BaseRealmConfig {
@JsonProperty("resource")
protected String resource;
@@ -34,8 +34,6 @@ public class BaseAdapterConfig extends BaseRealmConfig {
protected boolean exposeToken;
@JsonProperty("bearer-only")
protected boolean bearerOnly;
@JsonProperty("enable-basic-auth")
protected boolean enableBasicAuth;
@JsonProperty("public-client")
protected boolean publicClient;
@JsonProperty("credentials")
@@ -99,20 +97,12 @@ public class BaseAdapterConfig extends BaseRealmConfig {
}
public boolean isBearerOnly() {
return bearerOnly;
}
return bearerOnly;
}
public void setBearerOnly(boolean bearerOnly) {
this.bearerOnly = bearerOnly;
}
public boolean isEnableBasicAuth() {
return enableBasicAuth;
}
public void setEnableBasicAuth(boolean enableBasicAuth) {
this.enableBasicAuth = enableBasicAuth;
}
this.bearerOnly = bearerOnly;
}
public Map<String, String> getCredentials() {
return credentials;
@@ -1,7 +1,6 @@
package org.keycloak.representations.idm;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -22,11 +21,8 @@ public class ApplicationRepresentation {
protected Integer notBefore;
protected Boolean bearerOnly;
protected Boolean publicClient;
protected String protocol;
protected Map<String, String> attributes;
protected Boolean fullScopeAllowed;
protected Integer nodeReRegistrationTimeout;
protected Map<String, Integer> registeredNodes;
public String getId() {
return id;
@@ -147,36 +143,4 @@ public class ApplicationRepresentation {
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
this.fullScopeAllowed = fullScopeAllowed;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
public Integer getNodeReRegistrationTimeout() {
return nodeReRegistrationTimeout;
}
public void setNodeReRegistrationTimeout(Integer nodeReRegistrationTimeout) {
this.nodeReRegistrationTimeout = nodeReRegistrationTimeout;
}
public Map<String, Integer> getRegisteredNodes() {
return registeredNodes;
}
public void setRegisteredNodes(Map<String, Integer> registeredNodes) {
this.registeredNodes = registeredNodes;
}
}
@@ -1,7 +1,6 @@
package org.keycloak.representations.idm;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -17,8 +16,6 @@ public class OAuthClientRepresentation {
protected ClaimRepresentation claims;
protected Integer notBefore;
protected Boolean publicClient;
protected String protocol;
protected Map<String, String> attributes;
protected Boolean directGrantsOnly;
protected Boolean fullScopeAllowed;
@@ -111,19 +108,4 @@ public class OAuthClientRepresentation {
this.fullScopeAllowed = fullScopeAllowed;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}
@@ -43,8 +43,6 @@ public class RealmRepresentation {
protected String privateKey;
protected String publicKey;
protected String certificate;
protected String codeSecret;
protected RolesRepresentation roles;
protected List<String> defaultRoles;
protected Set<String> requiredCredentials;
@@ -62,8 +60,8 @@ public class RealmRepresentation {
protected String accountTheme;
protected String adminTheme;
protected String emailTheme;
protected Boolean eventsEnabled;
protected Long eventsExpiration;
protected boolean eventsEnabled;
protected long eventsExpiration;
protected List<String> eventsListeners;
public String getId() {
@@ -222,22 +220,6 @@ public class RealmRepresentation {
this.publicKey = publicKey;
}
public String getCertificate() {
return certificate;
}
public void setCertificate(String certificate) {
this.certificate = certificate;
}
public String getCodeSecret() {
return codeSecret;
}
public void setCodeSecret(String codeSecret) {
this.codeSecret = codeSecret;
}
public Boolean isPasswordCredentialGrantAllowed() {
return passwordCredentialGrantAllowed;
}
@@ -454,7 +436,7 @@ public class RealmRepresentation {
this.failureFactor = failureFactor;
}
public Boolean isEventsEnabled() {
public boolean isEventsEnabled() {
return eventsEnabled;
}
@@ -462,7 +444,7 @@ public class RealmRepresentation {
this.eventsEnabled = eventsEnabled;
}
public Long getEventsExpiration() {
public long getEventsExpiration() {
return eventsExpiration;
}
@@ -15,7 +15,7 @@ public class UserSessionRepresentation {
private String ipAddress;
private long start;
private long lastAccess;
private Map<String, String> applications = new HashMap<String, String>();
private Set<String> applications = new HashSet<String>();
private Map<String, String> clients = new HashMap<String, String>();
public String getId() {
@@ -58,11 +58,11 @@ public class UserSessionRepresentation {
this.lastAccess = lastAccess;
}
public Map<String, String> getApplications() {
public Set<String> getApplications() {
return applications;
}
public void setApplications(Map<String, String> applications) {
public void setApplications(Set<String> applications) {
this.applications = applications;
}
@@ -1,66 +0,0 @@
package org.keycloak.util;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import javax.security.auth.x500.X500Principal;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CertificateUtils {
static {
BouncyIntegration.init();
}
public static X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert, String subject) throws Exception {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
X500Principal subjectName = new X500Principal("CN=" + subject);
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
certGen.setSerialNumber(serialNumber);
certGen.setIssuerDN(caCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis() - 100000));
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 10);
certGen.setNotAfter(calendar.getTime());
certGen.setSubjectDN(subjectName);
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(caCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
new SubjectKeyIdentifierStructure(keyPair.getPublic()));
X509Certificate cert = certGen.generate(caPrivateKey, "BC"); // note: private key of CA
return cert;
}
public static X509Certificate generateV1SelfSignedCertificate(KeyPair keyPair, String subject) throws Exception {
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
X500Principal subjectPrincipal = new X500Principal("CN=" + subject);
certGen.setSerialNumber(serialNumber);
certGen.setIssuerDN(subjectPrincipal);
certGen.setNotBefore(new Date(System.currentTimeMillis() - 100000));
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 10);
certGen.setNotAfter(calendar.getTime());
certGen.setSubjectDN(subjectPrincipal);
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
X509Certificate cert = certGen.generate(keyPair.getPrivate(), "BC");
return cert;
}
}
@@ -1,74 +0,0 @@
package org.keycloak.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class HostUtils {
// Best effort to find the most proper hostname of this server.
public static String getHostName() {
return getHostNameImpl().trim().toLowerCase();
}
public static String getIpAddress() {
try {
String hostname = getHostName();
return InetAddress.getByName(hostname).getHostAddress();
} catch (UnknownHostException uhe) {
throw new IllegalStateException(uhe);
}
}
private static String getHostNameImpl() {
// Return bind address if available
String bindAddr = System.getProperty("jboss.bind.address");
if (bindAddr != null && !bindAddr.trim().equals("0.0.0.0")) {
return bindAddr;
}
// Fallback to qualified name
String qualifiedHostName = System.getProperty("jboss.qualified.host.name");
if (qualifiedHostName != null) {
return qualifiedHostName;
}
// If not on jboss env, let's try other possible fallbacks
// POSIX-like OSes including Mac should have this set
qualifiedHostName = System.getenv("HOSTNAME");
if (qualifiedHostName != null) {
return qualifiedHostName;
}
// Certain versions of Windows
qualifiedHostName = System.getenv("COMPUTERNAME");
if (qualifiedHostName != null) {
return qualifiedHostName;
}
try {
return NetworkUtils.canonize(getLocalHost().getHostName());
} catch (UnknownHostException uhe) {
uhe.printStackTrace();
return "unknown-host.unknown-domain";
}
}
/**
* Methods returns InetAddress for localhost
*
* @return InetAddress of the localhost
* @throws UnknownHostException if localhost could not be resolved
*/
private static InetAddress getLocalHost() throws UnknownHostException {
InetAddress addr;
try {
addr = InetAddress.getLocalHost();
} catch (ArrayIndexOutOfBoundsException e) { //this is workaround for mac osx bug see AS7-3223 and JGRP-1404
addr = InetAddress.getByName(null);
}
return addr;
}
}
@@ -17,7 +17,6 @@ import java.io.OutputStream;
public class JsonSerialization {
public static final ObjectMapper mapper = new ObjectMapper();
public static final ObjectMapper prettyMapper = new ObjectMapper();
public static final ObjectMapper sysPropertiesAwareMapper = new ObjectMapper(new SystemPropertiesJsonParserFactory());
static {
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
@@ -47,15 +46,7 @@ public class JsonSerialization {
}
public static <T> T readValue(InputStream bytes, Class<T> type) throws IOException {
return readValue(bytes, type, false);
}
public static <T> T readValue(InputStream bytes, Class<T> type, boolean replaceSystemProperties) throws IOException {
if (replaceSystemProperties) {
return sysPropertiesAwareMapper.readValue(bytes, type);
} else {
return mapper.readValue(bytes, type);
}
return mapper.readValue(bytes, type);
}
@@ -2,22 +2,18 @@ package org.keycloak.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import org.keycloak.constants.GenericConstants;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeystoreUtil {
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream trustStream = (filename.startsWith(GenericConstants.PROTOCOL_CLASSPATH))
?KeystoreUtil.class.getResourceAsStream(filename.replace(GenericConstants.PROTOCOL_CLASSPATH, ""))
:new FileInputStream(new File(filename));
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
File truststoreFile = new File(filename);
FileInputStream trustStream = new FileInputStream(truststoreFile);
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
return trustStore;
@@ -1,446 +0,0 @@
package org.keycloak.util;
/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Locale;
/**
* Utility methods related to networking.
*
* @author Brian Stansberry (c) 2011 Red Hat Inc.
*/
public class NetworkUtils {
private static final int MAX_GROUP_LENGTH = 4;
private static final int IPV6_LEN = 8;
private static final boolean can_bind_to_mcast_addr; // are we running on Linux ?
static {
can_bind_to_mcast_addr = checkForLinux() || checkForSolaris() || checkForHp();
}
public static String formatPossibleIpv6Address(String address) {
if(address == null) {
return null;
}
String ipv6Address;
if (address.startsWith("[") && address.endsWith("]")) {
ipv6Address = address.substring(0, address.lastIndexOf(']')).substring(1);
} else {
ipv6Address = address;
}
// Definitely not an IPv6, return untouched input.
if (!mayBeIPv6Address(ipv6Address)) {
return ipv6Address;
}
return '[' + canonize(ipv6Address) + ']';
}
/**
* <p>Convert IPv6 adress into RFC 5952 form.
* E.g. 2001:db8:0:1:0:0:0:1 -> 2001:db8:0:1::1</p>
*
* <p>Method is null safe, and if IPv4 address or host name is passed to the
* method it is returned wihout any processing.</p>
*
* <p>Method also supports IPv4 in IPv6 (e.g. 0:0:0:0:0:ffff:192.0.2.1 ->
* ::ffff:192.0.2.1), and zone ID (e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
* -> fe80::f0f0:c0c0:1919:1234%4).</p>
*
* @param ipv6Address String representing valid IPv6 address.
* @return String representing IPv6 in canonical form.
* @throws IllegalArgumentException if IPv6 format is unacceptable.
*/
public static String canonize(String ipv6Address) throws IllegalArgumentException {
if (ipv6Address == null) {
return null;
}
// Definitely not an IPv6, return untouched input.
if (!mayBeIPv6Address(ipv6Address)) {
return ipv6Address;
}
// Length without zone ID (%zone) or IPv4 address
int ipv6AddressLength = ipv6Address.length();
if (isIPv4AddressInIPv6(ipv6Address)) {
// IPv4 in IPv6
// e.g. 0:0:0:0:0:FFFF:127.0.0.1
int lastColonPos = ipv6Address.lastIndexOf(":");
int lastColonsPos = ipv6Address.lastIndexOf("::");
if (lastColonsPos >= 0 && lastColonPos == lastColonsPos + 1) {
// IPv6 part ends with two consecutive colons, last colon is part of IPv6 format.
// e.g. ::127.0.0.1
ipv6AddressLength = lastColonPos + 1;
} else {
// IPv6 part ends with only one colon, last colon is not part of IPv6 format.
// e.g. ::FFFF:127.0.0.1
ipv6AddressLength = lastColonPos;
}
} else if (ipv6Address.contains(":") && ipv6Address.contains("%")) {
// Zone ID
// e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
ipv6AddressLength = ipv6Address.lastIndexOf("%");
}
StringBuilder result = new StringBuilder();
char [][] groups = new char[IPV6_LEN][MAX_GROUP_LENGTH];
int groupCounter = 0;
int charInGroupCounter = 0;
// Index of the current zeroGroup, -1 means not found.
int zeroGroupIndex = -1;
int zeroGroupLength = 0;
// maximum length zero group, if there is more then one, then first one
int maxZeroGroupIndex = -1;
int maxZeroGroupLength = 0;
boolean isZero = true;
boolean groupStart = true;
/*
* Two consecutive colons, initial expansion.
* e.g. 2001:db8:0:0:1::1 -> 2001:db8:0:0:1:0:0:1
*/
StringBuilder expanded = new StringBuilder(ipv6Address);
int colonsPos = ipv6Address.indexOf("::");
int length = ipv6AddressLength;
int change = 0;
if (colonsPos >= 0 && colonsPos < ipv6AddressLength - 2) {
int colonCounter = 0;
for (int i = 0; i < ipv6AddressLength; i++) {
if (ipv6Address.charAt(i) == ':') {
colonCounter++;
}
}
if (colonsPos == 0) {
expanded.insert(0, "0");
change = change + 1;
}
for (int i = 0; i < IPV6_LEN - colonCounter; i++) {
expanded.insert(colonsPos + 1, "0:");
change = change + 2;
}
if (colonsPos == ipv6AddressLength - 2) {
expanded.setCharAt(colonsPos + change + 1, '0');
} else {
expanded.deleteCharAt(colonsPos + change + 1);
change = change - 1;
}
length = length + change;
}
// Processing one char at the time
for (int charCounter = 0; charCounter < length; charCounter++) {
char c = expanded.charAt(charCounter);
if (c >= 'A' && c <= 'F') {
c = (char) (c + 32);
}
if (c != ':') {
groups[groupCounter][charInGroupCounter] = c;
if (!(groupStart && c == '0')) {
++charInGroupCounter;
groupStart = false;
}
if (c != '0') {
isZero = false;
}
}
if (c == ':' || charCounter == (length - 1)) {
// We reached end of current group
if (isZero) {
++zeroGroupLength;
if (zeroGroupIndex == -1) {
zeroGroupIndex = groupCounter;
}
}
if (!isZero || charCounter == (length - 1)) {
// We reached end of zero group
if (zeroGroupLength > maxZeroGroupLength) {
maxZeroGroupLength = zeroGroupLength;
maxZeroGroupIndex = zeroGroupIndex;
}
zeroGroupLength = 0;
zeroGroupIndex = -1;
}
++groupCounter;
charInGroupCounter = 0;
isZero = true;
groupStart = true;
}
}
int numberOfGroups = groupCounter;
// Output results
for (groupCounter = 0; groupCounter < numberOfGroups; groupCounter++) {
if (maxZeroGroupLength <= 1 || groupCounter < maxZeroGroupIndex
|| groupCounter >= maxZeroGroupIndex + maxZeroGroupLength) {
for (int j = 0; j < MAX_GROUP_LENGTH; j++) {
if (groups[groupCounter][j] != 0) {
result.append(groups[groupCounter][j]);
}
}
if (groupCounter < (numberOfGroups - 1)
&& (groupCounter != maxZeroGroupIndex - 1
|| maxZeroGroupLength <= 1)) {
result.append(':');
}
} else if (groupCounter == maxZeroGroupIndex) {
result.append("::");
}
}
// Solve problem with three colons in IPv4 in IPv6 format
// e.g. 0:0:0:0:0:0:127.0.0.1 -> :::127.0.0.1 -> ::127.0.0.1
int resultLength = result.length();
if (result.charAt(resultLength - 1) == ':' && ipv6AddressLength < ipv6Address.length()
&& ipv6Address.charAt(ipv6AddressLength) == ':') {
result.delete(resultLength - 1, resultLength);
}
/*
* Append IPv4 from IPv4-in-IPv6 format or Zone ID
*/
for (int i = ipv6AddressLength; i < ipv6Address.length(); i++) {
result.append(ipv6Address.charAt(i));
}
return result.toString();
}
/**
* Heuristic check if string might be an IPv6 address.
*
* @param input Any string or null
* @return true, if input string contains only hex digits and at least two colons, before '.' or '%' character.
*/
private static boolean mayBeIPv6Address(String input) {
if (input == null) {
return false;
}
boolean result = false;
int colonsCounter = 0;
int length = input.length();
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
if (c == '.' || c == '%') {
// IPv4 in IPv6 or Zone ID detected, end of checking.
break;
}
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F') || c == ':')) {
return false;
} else if (c == ':') {
colonsCounter++;
}
}
if (colonsCounter >= 2) {
result = true;
}
return result;
}
/**
* Check if it is an IPv4 in IPv6 format.
* e.g. 0:0:0:0:0:FFFF:127.0.0.1
*
* @param ipv6Address the address
* @return true, if input string is an IPv4 address in IPv6 format.
*/
private static boolean isIPv4AddressInIPv6(String ipv6Address) {
return (ipv6Address.contains(":") && ipv6Address.contains("."));
}
/**
* Formats input address. For IPV4 returns simply host address, for IPV6 formats address according to <a
* href="http://tools.ietf.org/html/rfc5952">RFC5952</a> rules. It does not embed IPV6 address in '[', ']', since those are part of IPV6 URI literal.
*
* @param inet
* @return
*/
public static String formatAddress(InetAddress inet){
if(inet == null){
throw new NullPointerException();
}
if(inet instanceof Inet4Address){
return inet.getHostAddress();
} else if (inet instanceof Inet6Address){
byte[] byteRepresentation = inet.getAddress();
int[] hexRepresentation = new int[IPV6_LEN];
for(int i=0;i < hexRepresentation.length;i++){
hexRepresentation[i] = ( byteRepresentation[2*i] & 0xFF) << 8 | ( byteRepresentation[2*i+1] & 0xFF );
}
compactLongestZeroSequence(hexRepresentation);
return formatAddress6(hexRepresentation);
} else {
return inet.getHostAddress();
}
}
/**
* Converts socket address into string literal, which has form: 'address:port'. Example:<br>
* <ul>
* <li>127.0.0.1:8080</li>
* <li>dns.name.com:8080</li>
* <li>[0fe:1::20]:8080</li>
* <li>[::1]:8080</li>
* </ul>
* @param inet
* @return
*/
public static String formatAddress(InetSocketAddress inet){
if(inet == null){
throw new NullPointerException();
}
StringBuilder result = new StringBuilder();
if(inet.isUnresolved()){
result.append(inet.getHostName());
}else{
result.append(formatPossibleIpv6Address(formatAddress(inet.getAddress())));
}
result.append(":").append(inet.getPort());
return result.toString();
}
/**
* Converts IPV6 int[] representation into valid IPV6 string literal. Sequence of '-1' values are converted into '::'.
* @param hexRepresentation
* @return
*/
private static String formatAddress6(int[] hexRepresentation){
if(hexRepresentation == null){
throw new NullPointerException();
}
if(hexRepresentation.length != IPV6_LEN){
throw new IllegalArgumentException();
}
StringBuilder stringBuilder = new StringBuilder();
boolean inCompressedSection = false;
for(int i = 0;i<hexRepresentation.length;i++){
if(hexRepresentation[i] == -1){
if(!inCompressedSection){
inCompressedSection = true;
if(i == 0){
stringBuilder.append("::");
} else {
stringBuilder.append(':');
}
}
} else {
inCompressedSection = false;
stringBuilder.append(Integer.toHexString(hexRepresentation[i]));
if(i+1<hexRepresentation.length){
stringBuilder.append(":");
}
}
}
return stringBuilder.toString();
}
public static boolean isBindingToMulticastDressSupported() {
return can_bind_to_mcast_addr;
}
private static void compactLongestZeroSequence(int[] hexRepresentatoin){
int bestRunStart = -1;
int bestRunLen = -1;
boolean inRun = false;
int runStart = -1;
for(int i=0;i<hexRepresentatoin.length;i++){
if(hexRepresentatoin[i] == 0){
if(!inRun){
runStart = i;
inRun = true;
}
} else {
if(inRun){
inRun = false;
int runLen = i - runStart;
if(bestRunLen < 0){
bestRunStart = runStart;
bestRunLen = runLen;
} else {
if(runLen > bestRunLen){
bestRunStart = runStart;
bestRunLen = runLen;
}
}
}
}
}
if(bestRunStart >=0){
Arrays.fill(hexRepresentatoin, bestRunStart, bestRunStart + bestRunLen, -1);
}
}
private static boolean checkForLinux() {
return checkForPresence("os.name", "linux");
}
private static boolean checkForHp() {
return checkForPresence("os.name", "hp");
}
private static boolean checkForSolaris() {
return checkForPresence("os.name", "sun");
}
private static boolean checkForWindows() {
return checkForPresence("os.name", "win");
}
public static boolean checkForMac() {
return checkForPresence("os.name", "mac");
}
private static boolean checkForPresence(final String key, final String value) {
final String tmp = System.getProperty(key, value);
try {
return tmp != null && tmp.trim().toLowerCase(Locale.ENGLISH).startsWith(value);
} catch (Throwable t) {
return false;
}
}
// No instantiation
private NetworkUtils() {
}
}
@@ -1,51 +0,0 @@
package org.keycloak.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.io.IOContext;
import org.codehaus.jackson.map.MappingJsonFactory;
import org.codehaus.jackson.util.JsonParserDelegate;
/**
* Provides replacing of system properties for parsed values
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class SystemPropertiesJsonParserFactory extends MappingJsonFactory {
@Override
protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException {
JsonParser delegate = super._createJsonParser(data, offset, len, ctxt);
return new SystemPropertiesAwareJsonParser(delegate);
}
@Override
protected JsonParser _createJsonParser(Reader r, IOContext ctxt) throws IOException {
JsonParser delegate = super._createJsonParser(r, ctxt);
return new SystemPropertiesAwareJsonParser(delegate);
}
@Override
protected JsonParser _createJsonParser(InputStream in, IOContext ctxt) throws IOException {
JsonParser delegate = super._createJsonParser(in, ctxt);
return new SystemPropertiesAwareJsonParser(delegate);
}
public static class SystemPropertiesAwareJsonParser extends JsonParserDelegate {
public SystemPropertiesAwareJsonParser(JsonParser d) {
super(d);
}
@Override
public String getText() throws IOException {
String orig = super.getText();
return StringPropertyReplacer.replaceProperties(orig);
}
}
}
@@ -7,18 +7,12 @@ import java.util.Date;
*/
public class Time {
private static int offset;
public static int currentTime() {
return ((int) (System.currentTimeMillis() / 1000)) + offset;
return (int) (System.currentTimeMillis() / 1000);
}
public static Date toDate(int time) {
return new Date(((long) time ) * 1000);
}
public static void setOffset(int offset) {
Time.offset = offset;
}
}
-43
View File
@@ -1,8 +1,6 @@
package org.keycloak.util;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.regex.Pattern;
/**
@@ -25,45 +23,4 @@ public class UriUtils {
return originPattern.matcher(url).matches();
}
public static MultivaluedHashMap<String, String> decodeQueryString(String queryString) {
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
if (queryString == null || queryString.equals("")) return map;
String[] params = queryString.split("&");
for (String param : params)
{
if (param.indexOf('=') >= 0)
{
String[] nv = param.split("=", 2);
try
{
String name = URLDecoder.decode(nv[0], "UTF-8");
String val = nv.length > 1 ? nv[1] : "";
map.add(name, URLDecoder.decode(val, "UTF-8"));
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
else
{
try
{
String name = URLDecoder.decode(param, "UTF-8");
map.add(name, "");
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
}
return map;
}
public static String stripQueryParam(String url, String name){
return url.replaceFirst("[\\?&]"+name+"=[^&]*$|"+name+"=[^&]*&", "");
}
}
@@ -1,33 +0,0 @@
package org.keycloak;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.util.JsonSerialization;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class JsonParserTest {
@Test
public void testParsingSystemProps() throws IOException {
System.setProperty("my.host", "foo");
System.setProperty("con.pool.size", "200");
System.setProperty("allow.any.hostname", "true");
InputStream is = getClass().getClassLoader().getResourceAsStream("keycloak.json");
AdapterConfig config = JsonSerialization.readValue(is, AdapterConfig.class, true);
Assert.assertEquals("http://foo:8080/auth", config.getAuthServerUrl());
Assert.assertEquals("external", config.getSslRequired());
Assert.assertEquals("angular-product${non.existing}", config.getResource());
Assert.assertTrue(config.isPublicClient());
Assert.assertTrue(config.isAllowAnyHostname());
Assert.assertEquals(100, config.getCorsMaxAge());
Assert.assertEquals(200, config.getConnectionPoolSize());
}
}
@@ -72,7 +72,7 @@ public class RSAVerifierTest {
token = new AccessToken();
token.subject("CN=Client")
.issuer("domain")
.audience("domain")
.addAccess("service").addRole("admin");
}
@@ -213,7 +213,7 @@ public class RSAVerifierTest {
public void testTokenAuth() throws Exception {
token = new AccessToken();
token.subject("CN=Client")
.issuer("domain")
.audience("domain")
.addAccess("service").addRole("admin").verifyCaller(true);
String encoded = new JWSBuilder()
@@ -1,18 +1,13 @@
package org.keycloak;
import org.junit.Assert;
import junit.framework.Assert;
import org.junit.Test;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.util.JsonSerialization;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@ -23,7 +18,10 @@ import java.security.KeyPairGenerator;
public class SkeletonKeyTokenTest {
@Test
public void testToken() throws Exception {
AccessToken token = createSimpleToken();
AccessToken token = new AccessToken();
token.id("111");
token.addAccess("foo").addRole("admin");
token.addAccess("bar").addRole("user");
String json = JsonSerialization.writeValueAsString(token);
token = JsonSerialization.readValue(json, AccessToken.class);
@@ -36,7 +34,7 @@ public class SkeletonKeyTokenTest {
@Test
public void testRSA() throws Exception {
AccessToken token = createSimpleToken();
AccessToken token = new AccessToken();
token.id("111");
token.addAccess("foo").addRole("admin");
token.addAccess("bar").addRole("user");
@@ -53,59 +51,4 @@ public class SkeletonKeyTokenTest {
Assert.assertEquals("111", token.getId());
Assert.assertTrue(RSAProvider.verify(input, keyPair.getPublic()));
}
@Test
public void testSerialization() throws Exception {
AccessToken token = createSimpleToken();
IDToken idToken = new IDToken();
idToken.setEmail("joe@email.cz");
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
String encoded = new JWSBuilder()
.jsonContent(token)
.rsa256(keyPair.getPrivate());
String encodedIdToken = new JWSBuilder()
.jsonContent(idToken)
.rsa256(keyPair.getPrivate());
KeycloakSecurityContext ctx = new KeycloakSecurityContext(encoded, token, encodedIdToken, idToken);
KeycloakPrincipal principal = new KeycloakPrincipal("joe", ctx);
// Serialize
ByteArrayOutputStream bso = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bso);
oos.writeObject(principal);
oos.close();
// Deserialize
byte[] bytes = bso.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
principal = (KeycloakPrincipal)ois.readObject();
ctx = principal.getKeycloakSecurityContext();
token = ctx.getToken();
idToken = ctx.getIdToken();
System.out.println("Size of serialized principal: " + bytes.length);
Assert.assertEquals(encoded, ctx.getTokenString());
Assert.assertEquals(encodedIdToken, ctx.getIdTokenString());
Assert.assertEquals("111", token.getId());
Assert.assertEquals("111", token.getId());
Assert.assertTrue(token.getResourceAccess("foo").isUserInRole("admin"));
Assert.assertTrue(token.getResourceAccess("bar").isUserInRole("user"));
Assert.assertEquals("joe@email.cz", idToken.getEmail());
Assert.assertEquals("acme", ctx.getRealm());
ois.close();
}
private AccessToken createSimpleToken() {
AccessToken token = new AccessToken();
token.id("111");
token.issuer("acme");
token.addAccess("foo").addRole("admin");
token.addAccess("bar").addRole("user");
return token;
}
}
@@ -2,7 +2,6 @@ package org.keycloak.util;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -44,15 +43,4 @@ public class UriUtilsTest {
assertFalse(UriUtils.isOrigin(origin));
}
@Test
public void testStripQueryParam(){
assertEquals("http://localhost",UriUtils.stripQueryParam("http://localhost?login_hint=michael","login_hint"));
assertEquals("http://localhost",UriUtils.stripQueryParam("http://localhost?login_hint=michael@me.com","login_hint"));
assertEquals("http://localhost?param=test",UriUtils.stripQueryParam("http://localhost?param=test&login_hint=michael","login_hint"));
assertEquals("http://localhost?param=test",UriUtils.stripQueryParam("http://localhost?param=test&login_hint=michael@me.com","login_hint"));
assertEquals("http://localhost?param=test",UriUtils.stripQueryParam("http://localhost?login_hint=michael&param=test","login_hint"));
assertEquals("http://localhost?param=test",UriUtils.stripQueryParam("http://localhost?login_hint=michael@me.com&param=test","login_hint"));
assertEquals("http://localhost?pre=test&param=test",UriUtils.stripQueryParam("http://localhost?pre=test&login_hint=michael&param=test","login_hint"));
assertEquals("http://localhost?pre=test&param=test",UriUtils.stripQueryParam("http://localhost?pre=test&login_hint=michael@me.com&param=test","login_hint"));
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"auth-server-url" : "http://${my.host}:8080/auth",
"ssl-required" : "external",
"resource" : "angular-product${non.existing}",
"public-client" : true,
"allow-any-hostname": "${allow.any.hostname}",
"cors-max-age": 100,
"connection-pool-size": "${con.pool.size}"
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -49
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -26,16 +26,6 @@
<artifactId>keycloak-connections-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-connections-jpa-liquibase</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-connections-infinispan</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>
@@ -56,16 +46,6 @@
<artifactId>keycloak-model-sessions-mongo</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-sessions-infinispan</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-infinispan</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-events-jpa</artifactId>
@@ -143,17 +123,6 @@
<version>${project.version}</version>
</dependency>
<!-- saml -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-protocol</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-federation</artifactId>
</dependency>
<!-- mongo -->
<dependency>
<groupId>org.keycloak</groupId>
@@ -184,23 +153,6 @@
<dependency>
<groupId>de.idyl</groupId>
<artifactId>winzipaes</artifactId>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
+1 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -24,10 +24,6 @@
<groupId>net.iharder</groupId>
<artifactId>base64</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core-jaxrs</artifactId>
+43 -22
View File
@@ -21,9 +21,6 @@
<excludes>
<exclude>**/*.sh</exclude>
<exclude>welcome-content/*</exclude>
<exclude>**/modules/system/layers/base/org/picketlink/**</exclude>
<exclude>**/modules/system/layers/base/org/jboss/as/cli/**</exclude>
<exclude>**/modules/system/layers/base/org/jboss/aesh/**</exclude>
</excludes>
</fileSet>
<fileSet>
@@ -35,15 +32,14 @@
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>${project.build.directory}/unpacked/modules</directory>
<outputDirectory>keycloak/modules/system/layers/base</outputDirectory>
<includes>
<include>org/picketlink/**</include>
</includes>
<directory>${project.build.directory}/unpacked/deployments</directory>
<outputDirectory>keycloak/standalone/deployments</outputDirectory>
<excludes>
<exclude>keycloak-ds.xml</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/unpacked/deployments/auth-server.war/WEB-INF/classes/META-INF
</directory>
<directory>${project.build.directory}/unpacked/deployments/auth-server.war/WEB-INF/classes/META-INF</directory>
<outputDirectory>keycloak/standalone/configuration</outputDirectory>
<includes>
<include>keycloak-server.json</include>
@@ -57,23 +53,48 @@
<directory>${project.build.directory}/unpacked/adapter</directory>
<outputDirectory>keycloak</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}/unpacked/js-adapter</directory>
<outputDirectory>adapters/js-adapter</outputDirectory>
<includes>
<include>**/*.js</include>
<include>**/*.html</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/welcome-content</directory>
<outputDirectory>keycloak/welcome-content</outputDirectory>
<includes>
<include>*.*</include>
</includes>
</includes>
</fileSet>
</fileSets>
<files>
<file>
<source>src/main/themes/README.txt</source>
<outputDirectory>keycloak/standalone/configuration/themes</outputDirectory>
</file>
<file>
<source>src/main/providers/README.txt</source>
<outputDirectory>keycloak/standalone/configuration/providers</outputDirectory>
</file>
</files>
<dependencySets>
<dependencySet>
<unpack>false</unpack>
<useTransitiveDependencies>false</useTransitiveDependencies>
<includes>
<include>org.keycloak:keycloak-wildfly-adapter-dist:zip</include>
<include>org.keycloak:keycloak-as7-adapter-dist:zip</include>
<include>org.keycloak:keycloak-eap6-adapter-dist:zip</include>
</includes>
<outputDirectory>adapters</outputDirectory>
</dependencySet>
</dependencySets>
<!--
<moduleSets>
<moduleSet>
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
<include>org.keycloak:keycloak-wildfly-adapter-dist</include>
</includes>
<binaries>
<outputDirectory>adapters</outputDirectory>
<attachmentClassifier>zip</attachmentClassifier>
<includeDependencies>false</includeDependencies>
<unpack>false</unpack>
</binaries>
</moduleSet>
</moduleSets>
-->
</assembly>
+1 -44
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
@@ -26,42 +26,6 @@
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat6-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat7-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty81-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty91-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty92-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-eap6-adapter-dist</artifactId>
@@ -126,13 +90,6 @@
<outputDirectory>${project.build.directory}/unpacked/js-adapter</outputDirectory>
<includes>*.js</includes>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jboss-modules</artifactId>
<version>${project.version}</version>
<type>zip</type>
<outputDirectory>${project.build.directory}/unpacked/modules</outputDirectory>
</artifactItem>
</artifactItems>
<excludes>**/welcome-content/*</excludes>
</configuration>
@@ -1,2 +0,0 @@
Any provider implementation jars and libraries in this folder will be loaded by Keycloak. See the providers
section in the documentation for more details.
@@ -1,3 +0,0 @@
Themes to configure the look and feel of login pages and account management console. It's not recommended to
modify existing the built-in themes, instead you should create a new theme that extends a built-in theme. See the theme
section in the documentation for more details.
@@ -12,7 +12,7 @@
<xsl:template match="node()[name(.)='extensions']">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<extension module="org.keycloak.keycloak-subsystem"/>
<extension module="org.keycloak.keycloak-wildfly-subsystem"/>
</xsl:copy>
</xsl:template>
@@ -34,12 +34,7 @@
<xsl:template match="node()[name(.)='profile']">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<subsystem xmlns="urn:jboss:domain:keycloak:1.0">
<auth-server name="main-auth-server">
<enabled>true</enabled>
<web-context>auth</web-context>
</auth-server>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak:1.0"/>
</xsl:copy>
</xsl:template>
@@ -51,17 +46,12 @@
<login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
</authentication>
</security-domain>
<security-domain name="sp" cache-type="default">
<authentication>
<login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
</authentication>
</security-domain>
</xsl:copy>
</xsl:template>
<!-- for some reason, Wildfly 8 final decided to turn off management-native which means jboss-as-maven-plugin no
longer works -->
longer works -->
<xsl:template match="node()[name(.)='management-interfaces']">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
@@ -72,14 +62,14 @@
</xsl:template>
<!-- for some reason, Wildfly 8 final decided to turn off management-native which means jboss-as-maven-plugin no
longer works -->
longer works -->
<xsl:template match="node()[name(.)='socket-binding-group']">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<socket-binding name="management-native" interface="management" port="9999"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
+1 -3
View File
@@ -10,11 +10,9 @@
<fileSet>
<directory>${project.build.directory}/unpacked</directory>
<excludes>
<exclude>org/picketlink/**</exclude>
<exclude>org/keycloak/keycloak-undertow-adapter/**</exclude>
<exclude>org/keycloak/keycloak-wildfly-subsystem/**</exclude>
<exclude>org/keycloak/keycloak-wildfly-adapter/**</exclude>
<exclude>org/jboss/**</exclude>
<exclude>org/keycloak/keycloak-subsystem/**</exclude>
</excludes>
<outputDirectory>modules</outputDirectory>
</fileSet>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.1.0.Final</version>
<version>1.0.5.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
Loaded 100 of 1177 files, more files were not shown because too many files have changed in this diff. Show more