[KEYCLOAK-13141] - Supporting re-augmentation
This commit is contained in:
parent
48e4432e9d
commit
1db1deb066
35 changed files with 321 additions and 1243 deletions
6
.github/workflows/ci-x.yml
vendored
6
.github/workflows/ci-x.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 1.8
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
|
@ -38,7 +38,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 1.8
|
||||||
- name: Download Maven Repo
|
- name: Download Maven Repo
|
||||||
uses: actions/download-artifact@v1
|
uses: actions/download-artifact@v1
|
||||||
with:
|
with:
|
||||||
|
@ -61,7 +61,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 1.8
|
||||||
- name: Download Maven Repo
|
- name: Download Maven Repo
|
||||||
uses: actions/download-artifact@v1
|
uses: actions/download-artifact@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
<filter-name>Client Connection Filter</filter-name>
|
<filter-name>Client Connection Filter</filter-name>
|
||||||
<filter-class>org.keycloak.provider.wildfly.WildFlyClientConnectionServletFilter</filter-class>
|
<filter-class>org.keycloak.provider.wildfly.WildFlyRequestFilter</filter-class>
|
||||||
<async-supported>true</async-supported>
|
<async-supported>true</async-supported>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
|
|
|
@ -69,10 +69,10 @@
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<directory>../../quarkus/server/target</directory>
|
<directory>../../quarkus/server/target/lib</directory>
|
||||||
<outputDirectory>lib/</outputDirectory>
|
<outputDirectory>lib</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>keycloak-runner.jar</include>
|
<include>**/**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
|
|
|
@ -28,6 +28,8 @@ SERVER_OPTS="-Dkeycloak.home.dir=$DIRNAME/../ -Djboss.server.config.dir=$DIRNAME
|
||||||
DEBUG_MODE="${DEBUG:-false}"
|
DEBUG_MODE="${DEBUG:-false}"
|
||||||
DEBUG_PORT="${DEBUG_PORT:-8787}"
|
DEBUG_PORT="${DEBUG_PORT:-8787}"
|
||||||
|
|
||||||
|
IS_CONFIGURE="false"
|
||||||
|
|
||||||
while [ "$#" -gt 0 ]
|
while [ "$#" -gt 0 ]
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
@ -38,10 +40,13 @@ do
|
||||||
shift
|
shift
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
--config)
|
--config-file)
|
||||||
SERVER_OPTS="$SERVER_OPTS -Dkeycloak.config.file=$2"
|
SERVER_OPTS="$SERVER_OPTS -Dkeycloak.config.file=$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
config)
|
||||||
|
IS_CONFIGURE=true
|
||||||
|
;;
|
||||||
--)
|
--)
|
||||||
shift
|
shift
|
||||||
break;;
|
break;;
|
||||||
|
@ -71,6 +76,11 @@ if [ "$DEBUG_MODE" = "true" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CLASSPATH_OPTS="$DIRNAME/../providers/*:$DIRNAME/../lib/keycloak-runner.jar"
|
CLASSPATH_OPTS="$DIRNAME/../lib/quarkus-run.jar:$DIRNAME/../lib/main/*"
|
||||||
|
|
||||||
exec java $JAVA_OPTS $SERVER_OPTS -cp $CLASSPATH_OPTS io.quarkus.runner.GeneratedMain "$@"
|
if [ "$IS_CONFIGURE" = true ] ; then
|
||||||
|
echo "Updating the configuration and installing your custom providers, if any. Please wait."
|
||||||
|
exec java -Dquarkus.launch.rebuild=true $JAVA_OPTS $SERVER_OPTS -cp $CLASSPATH_OPTS io.quarkus.bootstrap.runner.QuarkusEntryPoint "$@"
|
||||||
|
else
|
||||||
|
exec java $JAVA_OPTS $SERVER_OPTS -cp $CLASSPATH_OPTS io.quarkus.bootstrap.runner.QuarkusEntryPoint "$@"
|
||||||
|
fi
|
|
@ -1,5 +1,5 @@
|
||||||
# Datasource
|
# Default Non-Production Grade Datasource
|
||||||
datasource.dialect=org.hibernate.dialect.H2Dialect
|
hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
|
||||||
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
||||||
datasource.url = jdbc:h2:file:${keycloak.home.dir}/data/keycloakdb;;AUTO_SERVER=TRUE
|
datasource.url = jdbc:h2:file:${keycloak.home.dir}/data/keycloakdb;;AUTO_SERVER=TRUE
|
||||||
datasource.username = sa
|
datasource.username = sa
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Installing Custom Providers
|
||||||
|
|
||||||
|
You should add to this directory your custom provider JAR files.
|
||||||
|
|
||||||
|
Once you have your providers in this directory you should run the following command to complete the installation:
|
||||||
|
|
||||||
|
```
|
||||||
|
${keycloak.home.dir}/bin/kc.sh config
|
||||||
|
```
|
|
@ -1 +0,0 @@
|
||||||
Copy custom providers into this directory then restart the Keycloak server.
|
|
|
@ -24,6 +24,11 @@
|
||||||
<artifactId>quarkus-arc-deployment</artifactId>
|
<artifactId>quarkus-arc-deployment</artifactId>
|
||||||
<version>${quarkus.version}</version>
|
<version>${quarkus.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-vertx-web-deployment</artifactId>
|
||||||
|
<version>${quarkus.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-quarkus-server</artifactId>
|
<artifactId>keycloak-quarkus-server</artifactId>
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.quarkus.deployment;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
public class BuildClassLoader extends URLClassLoader {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(BuildClassLoader.class);
|
||||||
|
|
||||||
|
public BuildClassLoader() {
|
||||||
|
super(new URL[] {}, Thread.currentThread().getContextClassLoader());
|
||||||
|
String homeDir = System.getProperty("keycloak.home.dir");
|
||||||
|
|
||||||
|
if (homeDir == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File providersDir = new File(homeDir + File.separator + "providers");
|
||||||
|
|
||||||
|
if (providersDir.isDirectory()) {
|
||||||
|
for (File file : providersDir.listFiles(new JarFilter())) {
|
||||||
|
try {
|
||||||
|
addURL(file.toURI().toURL());
|
||||||
|
logger.debug("Loading providers from " + file.getAbsolutePath());
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException("Failed to add provider JAR at " + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JarFilter implements FilenameFilter {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File dir, String name) {
|
||||||
|
return name.toLowerCase().endsWith(".jar");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.quarkus.deployment;
|
package org.keycloak.quarkus.deployment;
|
||||||
|
|
||||||
|
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -7,24 +8,21 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
import io.quarkus.hibernate.orm.deployment.HibernateOrmConfig;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
|
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory;
|
import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory;
|
||||||
import org.keycloak.connections.jpa.DelegatingDialect;
|
|
||||||
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProviderFactory;
|
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProviderFactory;
|
||||||
import org.keycloak.connections.jpa.updater.liquibase.conn.DefaultLiquibaseConnectionProvider;
|
import org.keycloak.connections.jpa.updater.liquibase.conn.DefaultLiquibaseConnectionProvider;
|
||||||
import org.keycloak.provider.KeycloakDeploymentInfo;
|
import org.keycloak.provider.KeycloakDeploymentInfo;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.provider.ProviderManager;
|
import org.keycloak.provider.ProviderManager;
|
||||||
import org.keycloak.provider.Spi;
|
import org.keycloak.provider.Spi;
|
||||||
import org.keycloak.provider.quarkus.QuarkusClientConnectionFilter;
|
import org.keycloak.provider.quarkus.QuarkusRequestFilter;
|
||||||
import org.keycloak.runtime.KeycloakRecorder;
|
import org.keycloak.runtime.KeycloakRecorder;
|
||||||
import org.keycloak.transaction.JBossJtaTransactionManagerLookup;
|
import org.keycloak.transaction.JBossJtaTransactionManagerLookup;
|
||||||
|
|
||||||
import io.quarkus.arc.deployment.BeanContainerListenerBuildItem;
|
|
||||||
import io.quarkus.deployment.annotations.BuildProducer;
|
import io.quarkus.deployment.annotations.BuildProducer;
|
||||||
import io.quarkus.deployment.annotations.BuildStep;
|
import io.quarkus.deployment.annotations.BuildStep;
|
||||||
import io.quarkus.deployment.annotations.ExecutionTime;
|
import io.quarkus.deployment.annotations.ExecutionTime;
|
||||||
|
@ -32,6 +30,7 @@ import io.quarkus.deployment.annotations.Record;
|
||||||
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
||||||
import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
|
import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
|
||||||
import io.quarkus.vertx.http.deployment.FilterBuildItem;
|
import io.quarkus.vertx.http.deployment.FilterBuildItem;
|
||||||
|
import org.keycloak.util.Environment;
|
||||||
|
|
||||||
class KeycloakProcessor {
|
class KeycloakProcessor {
|
||||||
|
|
||||||
|
@ -40,41 +39,50 @@ class KeycloakProcessor {
|
||||||
return new FeatureBuildItem("keycloak");
|
return new FeatureBuildItem("keycloak");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Record(ExecutionTime.STATIC_INIT)
|
|
||||||
@BuildStep
|
|
||||||
void configureHibernate(KeycloakRecorder recorder, List<PersistenceUnitDescriptorBuildItem> descriptors) {
|
|
||||||
// TODO: ORM extension is going to provide build items that we can rely on to create our own PU instead of relying
|
|
||||||
// on the parsed descriptor and assume that the order that build steps are executed is always the same (although dialect
|
|
||||||
// is only created during runtime)
|
|
||||||
ParsedPersistenceXmlDescriptor unit = descriptors.get(0).getDescriptor();
|
|
||||||
unit.setTransactionType(PersistenceUnitTransactionType.JTA);
|
|
||||||
unit.getProperties().setProperty(AvailableSettings.DIALECT, DelegatingDialect.class.getName());
|
|
||||||
unit.getProperties().setProperty(AvailableSettings.QUERY_STARTUP_CHECKING, Boolean.FALSE.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Record(ExecutionTime.STATIC_INIT)
|
|
||||||
@BuildStep
|
|
||||||
void configureDataSource(KeycloakRecorder recorder, BuildProducer<BeanContainerListenerBuildItem> container) {
|
|
||||||
container.produce(new BeanContainerListenerBuildItem(recorder.configureDataSource()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>Configures the persistence unit for Quarkus.
|
||||||
* Load the built-in provider factories during build time so we don't spend time looking up them at runtime.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>The main reason we have this build step is because we re-use the same persistence unit from {@code keycloak-model-jpa}
|
||||||
* User-defined providers are going to be loaded at startup
|
* module, the same used by the Wildfly distribution. The {@code hibernate-orm} extension expects that the dialect is statically
|
||||||
* </p>
|
* set to the persistence unit if there is any from the classpath and use this method to obtain the dialect from the configuration
|
||||||
|
* file so that we can re-augment the application with whatever dialect we want. In addition to the dialect, we should also be
|
||||||
|
* allowed to set any additional defaults that we think that makes sense.
|
||||||
|
*
|
||||||
|
* @param recorder
|
||||||
|
* @param config
|
||||||
|
* @param descriptors
|
||||||
*/
|
*/
|
||||||
@Record(ExecutionTime.STATIC_INIT)
|
@Record(ExecutionTime.STATIC_INIT)
|
||||||
@BuildStep
|
@BuildStep
|
||||||
void configureBuiltInProviders(KeycloakRecorder recorder) {
|
void configureHibernate(KeycloakRecorder recorder, HibernateOrmConfig config, List<PersistenceUnitDescriptorBuildItem> descriptors) {
|
||||||
recorder.configSessionFactory(loadBuiltInFactories());
|
PersistenceUnitDescriptor unit = descriptors.get(0).asOutputPersistenceUnitDefinition().getActualHibernateDescriptor();
|
||||||
|
|
||||||
|
unit.getProperties().setProperty(AvailableSettings.DIALECT, config.dialect.get());
|
||||||
|
unit.getProperties().setProperty(AvailableSettings.JPA_TRANSACTION_TYPE, PersistenceUnitTransactionType.JTA.name());
|
||||||
|
unit.getProperties().setProperty(AvailableSettings.QUERY_STARTUP_CHECKING, Boolean.FALSE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Spi, Set<Class<? extends ProviderFactory>>> loadBuiltInFactories() {
|
/**
|
||||||
|
* <p>Load the built-in provider factories during build time so we don't spend time looking up them at runtime.
|
||||||
|
*
|
||||||
|
* <p>User-defined providers are going to be loaded at startup</p>
|
||||||
|
*
|
||||||
|
* @param recorder
|
||||||
|
*/
|
||||||
|
@Record(ExecutionTime.STATIC_INIT)
|
||||||
|
@BuildStep
|
||||||
|
void configureProviders(KeycloakRecorder recorder) {
|
||||||
|
recorder.configSessionFactory(loadFactories(), Environment.isRebuild());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BuildStep
|
||||||
|
void initializeRouter(BuildProducer<FilterBuildItem> routes) {
|
||||||
|
routes.produce(new FilterBuildItem(new QuarkusRequestFilter(), FilterBuildItem.AUTHORIZATION - 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Spi, Set<Class<? extends ProviderFactory>>> loadFactories() {
|
||||||
ProviderManager pm = new ProviderManager(
|
ProviderManager pm = new ProviderManager(
|
||||||
KeycloakDeploymentInfo.create().services(), Thread.currentThread().getContextClassLoader(),
|
KeycloakDeploymentInfo.create().services(), new BuildClassLoader(),
|
||||||
Config.scope().getArray("providers"));
|
Config.scope().getArray("providers"));
|
||||||
Map<Spi, Set<Class<? extends ProviderFactory>>> result = new HashMap<>();
|
Map<Spi, Set<Class<? extends ProviderFactory>>> result = new HashMap<>();
|
||||||
|
|
||||||
|
@ -98,9 +106,4 @@ class KeycloakProcessor {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@BuildStep
|
|
||||||
void initializeRouter(BuildProducer<FilterBuildItem> routes) {
|
|
||||||
routes.produce(new FilterBuildItem(new QuarkusClientConnectionFilter(), FilterBuildItem.AUTHORIZATION - 10));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
quarkus.log.level = INFO
|
quarkus.http.root-path=/auth
|
||||||
|
|
||||||
quarkus.application.name=Keycloak
|
quarkus.application.name=Keycloak
|
||||||
resteasy.disable.html.sanitizer = true
|
quarkus.banner.enabled=false
|
|
@ -1,7 +1,7 @@
|
||||||
hostname.default.frontendUrl = ${keycloak.frontendUrl:}
|
hostname.default.frontendUrl = ${keycloak.frontendUrl:}
|
||||||
|
|
||||||
# Datasource
|
# Datasource
|
||||||
datasource.dialect=org.hibernate.dialect.H2Dialect
|
hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
|
||||||
datasource.jdbc.transactions=xa
|
datasource.jdbc.transactions=xa
|
||||||
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
||||||
datasource.url = jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
|
datasource.url = jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<quarkus.version>1.6.0.CR1</quarkus.version>
|
<quarkus.version>999-SNAPSHOT</quarkus.version>
|
||||||
<resteasy.version>4.5.5.Final</resteasy.version>
|
<resteasy.version>4.5.5.Final</resteasy.version>
|
||||||
<jackson.version>2.10.4</jackson.version>
|
<jackson.version>2.10.4</jackson.version>
|
||||||
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
||||||
|
@ -138,4 +138,32 @@
|
||||||
<module>server</module>
|
<module>server</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
<!-- Temporary definition while Quarkus 1.7.0.Final is not released -->
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>dependency-snapshots-repo</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<!-- Temporary definition while Quarkus 1.7.0.Final is not released -->
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>dependency-snapshots-repo</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak;
|
package org.keycloak;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -13,7 +14,6 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.provider.KeycloakDeploymentInfo;
|
import org.keycloak.provider.KeycloakDeploymentInfo;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.provider.ProviderLoader;
|
import org.keycloak.provider.ProviderLoader;
|
||||||
import org.keycloak.provider.ProviderManager;
|
|
||||||
import org.keycloak.provider.ProviderManagerRegistry;
|
import org.keycloak.provider.ProviderManagerRegistry;
|
||||||
import org.keycloak.provider.Spi;
|
import org.keycloak.provider.Spi;
|
||||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||||
|
@ -37,23 +37,25 @@ public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionF
|
||||||
}
|
}
|
||||||
|
|
||||||
private static QuarkusKeycloakSessionFactory INSTANCE;
|
private static QuarkusKeycloakSessionFactory INSTANCE;
|
||||||
private Map<Spi, Set<Class<? extends ProviderFactory>>> factories;
|
private final Boolean reaugmented;
|
||||||
|
private final Map<Spi, Set<Class<? extends ProviderFactory>>> factories;
|
||||||
|
|
||||||
public QuarkusKeycloakSessionFactory(Map<Spi, Set<Class<? extends ProviderFactory>>> factories) {
|
public QuarkusKeycloakSessionFactory(Map<Spi, Set<Class<? extends ProviderFactory>>> factories, Boolean reaugmented) {
|
||||||
this.factories = factories;
|
this.factories = factories;
|
||||||
|
this.reaugmented = reaugmented;
|
||||||
}
|
}
|
||||||
|
|
||||||
private QuarkusKeycloakSessionFactory() {
|
private QuarkusKeycloakSessionFactory() {
|
||||||
|
reaugmented = false;
|
||||||
|
factories = Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
serverStartupTimestamp = System.currentTimeMillis();
|
serverStartupTimestamp = System.currentTimeMillis();
|
||||||
ProviderLoader userProviderLoader = createUserProviderLoader();
|
spis = factories.keySet();
|
||||||
spis = loadRuntimeSpis(userProviderLoader);
|
|
||||||
|
|
||||||
for (Spi spi : spis) {
|
for (Spi spi : spis) {
|
||||||
loadUserProviders(spi, userProviderLoader);
|
|
||||||
for (Class<? extends ProviderFactory> factoryClazz : factories.get(spi)) {
|
for (Class<? extends ProviderFactory> factoryClazz : factories.get(spi)) {
|
||||||
ProviderFactory factory = lookupProviderFactory(factoryClazz);
|
ProviderFactory factory = lookupProviderFactory(factoryClazz);
|
||||||
Config.Scope scope = Config.scope(spi.getName(), factory.getId());
|
Config.Scope scope = Config.scope(spi.getName(), factory.getId());
|
||||||
|
@ -86,27 +88,6 @@ public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionF
|
||||||
ProviderManagerRegistry.SINGLETON.setDeployer(this);
|
ProviderManagerRegistry.SINGLETON.setDeployer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Spi> loadRuntimeSpis(ProviderLoader runtimeLoader) {
|
|
||||||
// most of the time SPIs loaded at build time are enough but under certain circumstances (e.g.: testsuite) we may
|
|
||||||
// want to load additional SPIs at runtime only from the JARs deployed at the providers dir
|
|
||||||
List<Spi> loaded = runtimeLoader.loadSpis();
|
|
||||||
|
|
||||||
if (loaded.isEmpty()) {
|
|
||||||
return factories.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<Spi> spis = new HashSet<>(factories.keySet());
|
|
||||||
|
|
||||||
spis.addAll(loaded);
|
|
||||||
|
|
||||||
return spis;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ProviderLoader createUserProviderLoader() {
|
|
||||||
return UserProviderLoader
|
|
||||||
.create(KeycloakDeploymentInfo.create().services(), Thread.currentThread().getContextClassLoader());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ProviderFactory lookupProviderFactory(Class<? extends ProviderFactory> factoryClazz) {
|
private ProviderFactory lookupProviderFactory(Class<? extends ProviderFactory> factoryClazz) {
|
||||||
ProviderFactory factory;
|
ProviderFactory factory;
|
||||||
|
|
||||||
|
@ -154,19 +135,4 @@ public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionF
|
||||||
logger.debugv("No default provider for {0}", spi.getName());
|
logger.debugv("No default provider for {0}", spi.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadUserProviders(Spi spi, ProviderLoader loader) {
|
|
||||||
//TODO: support loading providers from CDI. We should probably consider writing providers using CDI for Quarkus, much easier
|
|
||||||
// to develop and integrate with
|
|
||||||
List<ProviderFactory> load = loader.load(spi);
|
|
||||||
|
|
||||||
for (ProviderFactory factory : load) {
|
|
||||||
factories.computeIfAbsent(spi, new Function<Spi, Set<Class<? extends ProviderFactory>>>() {
|
|
||||||
@Override
|
|
||||||
public Set<Class<? extends ProviderFactory>> apply(Spi spi) {
|
|
||||||
return new HashSet<>();
|
|
||||||
}
|
|
||||||
}).add(factory.getClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
package org.keycloak;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.provider.DefaultProviderLoader;
|
|
||||||
import org.keycloak.provider.KeycloakDeploymentInfo;
|
|
||||||
import org.keycloak.provider.ProviderLoader;
|
|
||||||
|
|
||||||
class UserProviderLoader {
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(UserProviderLoader.class);
|
|
||||||
|
|
||||||
static ProviderLoader create(KeycloakDeploymentInfo info, ClassLoader parentClassLoader) {
|
|
||||||
return new DefaultProviderLoader(info, createClassLoader(parentClassLoader));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ClassLoader createClassLoader(ClassLoader parent) {
|
|
||||||
String homeDir = System.getProperty("keycloak.home.dir");
|
|
||||||
|
|
||||||
if (homeDir == null) {
|
|
||||||
// don't load resources from classpath
|
|
||||||
return new ClassLoader() {
|
|
||||||
@Override
|
|
||||||
public Enumeration<URL> getResources(String name) throws IOException {
|
|
||||||
return Collections.emptyEnumeration();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<URL> urls = new LinkedList<URL>();
|
|
||||||
File dir = new File(homeDir + File.separator + "providers");
|
|
||||||
|
|
||||||
if (dir.isDirectory()) {
|
|
||||||
for (File file : dir.listFiles(new JarFilter())) {
|
|
||||||
urls.add(file.toURI().toURL());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Loading providers from " + urls.toString());
|
|
||||||
|
|
||||||
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parent) {
|
|
||||||
@Override
|
|
||||||
public Enumeration<URL> getResources(String name) throws IOException {
|
|
||||||
Enumeration<URL> resources = findResources(name);
|
|
||||||
List<URL> result = new ArrayList<>();
|
|
||||||
|
|
||||||
while (resources.hasMoreElements()) {
|
|
||||||
URL url = resources.nextElement();
|
|
||||||
|
|
||||||
if (url.toString().contains(dir.getAbsolutePath())) {
|
|
||||||
result.add(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.enumeration(result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class JarFilter implements FilenameFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accept(File dir, String name) {
|
|
||||||
return name.toLowerCase().endsWith(".jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -125,6 +125,13 @@ public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSou
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need a better namespace resolution so that we don't need to add Quarkus extensions manually. Maybe the easiest
|
||||||
|
* path is to just have the "keycloak" namespace for Keycloak-specific properties.
|
||||||
|
*
|
||||||
|
* @param key the key to transform
|
||||||
|
* @return the same key but prefixed with the namespace
|
||||||
|
*/
|
||||||
private static String transformKey(String key) {
|
private static String transformKey(String key) {
|
||||||
String namespace;
|
String namespace;
|
||||||
String[] keyParts = key.split("\\.");
|
String[] keyParts = key.split("\\.");
|
||||||
|
@ -138,6 +145,7 @@ public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSou
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (extension) {
|
switch (extension) {
|
||||||
|
case "hibernate-orm":
|
||||||
case "datasource":
|
case "datasource":
|
||||||
case "http":
|
case "http":
|
||||||
case "log":
|
case "log":
|
||||||
|
|
|
@ -17,11 +17,9 @@
|
||||||
|
|
||||||
package org.keycloak.provider.quarkus;
|
package org.keycloak.provider.quarkus;
|
||||||
|
|
||||||
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
|
|
||||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.common.util.Resteasy;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.services.filters.AbstractClientConnectionFilter;
|
import org.keycloak.services.filters.AbstractRequestFilter;
|
||||||
|
|
||||||
import io.vertx.core.AsyncResult;
|
import io.vertx.core.AsyncResult;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
|
@ -35,8 +33,9 @@ import io.vertx.ext.web.RoutingContext;
|
||||||
* <p>The filter itself runs in a event loop and should delegate to worker threads any blocking code (for now, all requests are handled
|
* <p>The filter itself runs in a event loop and should delegate to worker threads any blocking code (for now, all requests are handled
|
||||||
* as blocking).
|
* as blocking).
|
||||||
*/
|
*/
|
||||||
public class QuarkusClientConnectionFilter extends AbstractClientConnectionFilter implements Handler<RoutingContext> {
|
public class QuarkusRequestFilter extends AbstractRequestFilter implements Handler<RoutingContext> {
|
||||||
|
|
||||||
|
private static final String KEYCLOAK_SESSION_KEY = KeycloakSession.class.getName();
|
||||||
private static final Handler<AsyncResult<Object>> EMPTY_RESULT = result -> {
|
private static final Handler<AsyncResult<Object>> EMPTY_RESULT = result -> {
|
||||||
// we don't really care about the result because any exception thrown should be handled by the parent class
|
// we don't really care about the result because any exception thrown should be handled by the parent class
|
||||||
};
|
};
|
||||||
|
@ -49,6 +48,10 @@ public class QuarkusClientConnectionFilter extends AbstractClientConnectionFilte
|
||||||
// in the event loop
|
// in the event loop
|
||||||
context.vertx().executeBlocking(promise -> filter(clientConnection, (session) -> {
|
context.vertx().executeBlocking(promise -> filter(clientConnection, (session) -> {
|
||||||
try {
|
try {
|
||||||
|
// we need to close the session before response is sent to the client, otherwise subsequent requests could
|
||||||
|
// not get the latest state because the session from the previous request is still being closed
|
||||||
|
// other methods from Vert.x to add a handler to the response works asynchronously
|
||||||
|
context.response().headersEndHandler(event -> close(session));
|
||||||
context.next();
|
context.next();
|
||||||
promise.complete();
|
promise.complete();
|
||||||
} catch (Exception cause) {
|
} catch (Exception cause) {
|
||||||
|
@ -59,6 +62,11 @@ public class QuarkusClientConnectionFilter extends AbstractClientConnectionFilte
|
||||||
}), EMPTY_RESULT);
|
}), EMPTY_RESULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isAutoClose() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private ClientConnection createClientConnection(HttpServerRequest request) {
|
private ClientConnection createClientConnection(HttpServerRequest request) {
|
||||||
return new ClientConnection() {
|
return new ClientConnection() {
|
||||||
@Override
|
@Override
|
|
@ -29,10 +29,6 @@ public class KeycloakRecorder {
|
||||||
CONFIG = (SmallRyeConfig) SmallRyeConfigProviderResolver.instance().getConfig();
|
CONFIG = (SmallRyeConfig) SmallRyeConfigProviderResolver.instance().getConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDatabaseDialect() {
|
|
||||||
return CONFIG.getRawValue("quarkus.datasource.dialect");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void configureLiquibase(Map<String, List<String>> services) {
|
public void configureLiquibase(Map<String, List<String>> services) {
|
||||||
LogFactory.setInstance(new LogFactory() {
|
LogFactory.setInstance(new LogFactory() {
|
||||||
KeycloakLogger logger = new KeycloakLogger();
|
KeycloakLogger logger = new KeycloakLogger();
|
||||||
|
@ -57,19 +53,7 @@ public class KeycloakRecorder {
|
||||||
ServiceLocator.setInstance(new FastServiceLocator(services));
|
ServiceLocator.setInstance(new FastServiceLocator(services));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeanContainerListener configureDataSource() {
|
public void configSessionFactory(Map<Spi, Set<Class<? extends ProviderFactory>>> factories, Boolean reaugmented) {
|
||||||
return new BeanContainerListener() {
|
QuarkusKeycloakSessionFactory.setInstance(new QuarkusKeycloakSessionFactory(factories, reaugmented));
|
||||||
@Override
|
|
||||||
public void created(BeanContainer container) {
|
|
||||||
String driver = CONFIG.getRawValue("quarkus.datasource.driver");
|
|
||||||
DataSourceSupport instance = container.instance(DataSourceSupport.class);
|
|
||||||
DataSourceSupport.Entry entry = instance.entries.get(DataSourceUtil.DEFAULT_DATASOURCE_NAME);
|
|
||||||
entry.resolvedDriverClass = driver;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void configSessionFactory(Map<Spi, Set<Class<? extends ProviderFactory>>> factories) {
|
|
||||||
QuarkusKeycloakSessionFactory.setInstance(new QuarkusKeycloakSessionFactory(factories));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.util;
|
||||||
|
|
||||||
|
public final class Environment {
|
||||||
|
|
||||||
|
public static Boolean isRebuild() {
|
||||||
|
return Boolean.valueOf(System.getProperty("quarkus.launch.rebuild"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,7 +63,6 @@
|
||||||
<artifactId>quarkus-maven-plugin</artifactId>
|
<artifactId>quarkus-maven-plugin</artifactId>
|
||||||
<version>${quarkus.version}</version>
|
<version>${quarkus.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<uberJar>true</uberJar>
|
|
||||||
<finalName>keycloak</finalName>
|
<finalName>keycloak</finalName>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
hostname.default.frontendUrl = ${keycloak.frontendUrl:}
|
hostname.default.frontendUrl = ${keycloak.frontendUrl:}
|
||||||
|
|
||||||
# Datasource
|
# Default Non-Production Grade Datasource
|
||||||
datasource.dialect=org.hibernate.dialect.H2Dialect
|
hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
|
||||||
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
||||||
datasource.url = jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
|
datasource.url = jdbc:h2:file:${keycloak.home.dir:~}/data/keycloakdb;;AUTO_SERVER=TRUE
|
||||||
datasource.username = sa
|
datasource.username = sa
|
||||||
datasource.password = keycloak
|
datasource.password = keycloak
|
||||||
datasource.jdbc.transactions=xa
|
datasource.jdbc.transactions=xa
|
|
@ -1,4 +1,9 @@
|
||||||
#quarkus.log.level = DEBUG
|
#quarkus.log.level = DEBUG
|
||||||
|
quarkus.package.output-name=keycloak
|
||||||
|
quarkus.package.type=mutable-jar
|
||||||
|
quarkus.package.output-directory=lib
|
||||||
|
quarkus.package.user-providers-directory=../providers
|
||||||
|
|
||||||
quarkus.http.root-path=/auth
|
quarkus.http.root-path=/auth
|
||||||
quarkus.application.name=Keycloak
|
quarkus.application.name=Keycloak
|
||||||
quarkus.banner.enabled=false
|
quarkus.banner.enabled=false
|
|
@ -18,8 +18,6 @@ package org.keycloak.services.filters;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.common.util.Resteasy;
|
import org.keycloak.common.util.Resteasy;
|
||||||
|
@ -29,9 +27,9 @@ import org.keycloak.models.KeycloakTransactionManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
|
|
||||||
public abstract class AbstractClientConnectionFilter {
|
public abstract class AbstractRequestFilter {
|
||||||
|
|
||||||
public void filter(ClientConnection clientConnection, Consumer<KeycloakSession> next) {
|
protected void filter(ClientConnection clientConnection, Consumer<KeycloakSession> next) {
|
||||||
KeycloakSessionFactory sessionFactory = KeycloakApplication.getSessionFactory();
|
KeycloakSessionFactory sessionFactory = KeycloakApplication.getSessionFactory();
|
||||||
KeycloakSession session = sessionFactory.create();
|
KeycloakSession session = sessionFactory.create();
|
||||||
|
|
||||||
|
@ -47,11 +45,13 @@ public abstract class AbstractClientConnectionFilter {
|
||||||
tx.setRollbackOnly();
|
tx.setRollbackOnly();
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
if (isAutoClose()) {
|
||||||
close(session);
|
close(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void close(KeycloakSession session) {
|
protected void close(KeycloakSession session) {
|
||||||
KeycloakTransactionManager tx = session.getTransactionManager();
|
KeycloakTransactionManager tx = session.getTransactionManager();
|
||||||
if (tx.isActive()) {
|
if (tx.isActive()) {
|
||||||
if (tx.getRollbackOnly()) {
|
if (tx.getRollbackOnly()) {
|
||||||
|
@ -63,4 +63,14 @@ public abstract class AbstractClientConnectionFilter {
|
||||||
|
|
||||||
session.close();
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Indicates whether or not resources should be close as part of the execution of the {@link #filter(ClientConnection, Consumer)}
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @return true if resources should be close automatically. Otherwise, false.
|
||||||
|
*/
|
||||||
|
protected boolean isAutoClose() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<project>
|
||||||
|
|
||||||
|
<target name="config">
|
||||||
|
<bin-chmod/>
|
||||||
|
<echo>Re-augmenting...</echo>
|
||||||
|
<exec osfamily="unix" dir="${auth.server.home}/bin" executable="./kc.sh" failonerror="true">
|
||||||
|
<arg value="config"/>
|
||||||
|
</exec>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<macrodef name="bin-chmod">
|
||||||
|
<sequential>
|
||||||
|
<chmod perm="ug+x">
|
||||||
|
<fileset dir="${auth.server.home}/bin">
|
||||||
|
<include name="*.sh"/>
|
||||||
|
</fileset>
|
||||||
|
</chmod>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
</project>
|
|
@ -172,6 +172,26 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-antrun-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>ant-generate-default</id>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<target>
|
||||||
|
<ant antfile="ant/configure.xml" target="config" >
|
||||||
|
<property name="auth.server.home">${auth.server.home}</property>
|
||||||
|
</ant>
|
||||||
|
</target>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ hostname.default.frontendUrl = ${keycloak.frontendUrl:}
|
||||||
datasource.jdbc.transactions=xa
|
datasource.jdbc.transactions=xa
|
||||||
|
|
||||||
# H2
|
# H2
|
||||||
datasource.dialect=org.hibernate.dialect.H2Dialect
|
hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
|
||||||
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
datasource.driver=org.h2.jdbcx.JdbcDataSource
|
||||||
datasource.url = jdbc:h2:file:${keycloak.home.dir}/data/keycloakdb;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1
|
datasource.url = jdbc:h2:file:${keycloak.home.dir}/data/keycloakdb;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1
|
||||||
datasource.username = sa
|
datasource.username = sa
|
||||||
|
|
|
@ -50,7 +50,7 @@ import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.testsuite.JsonConfigProviderFactory;
|
import org.keycloak.testsuite.JsonConfigProviderFactory;
|
||||||
import org.keycloak.testsuite.KeycloakServer;
|
import org.keycloak.testsuite.KeycloakServer;
|
||||||
import org.keycloak.testsuite.UndertowClientConnectionServletFilter;
|
import org.keycloak.testsuite.UndertowRequestFilter;
|
||||||
import org.keycloak.testsuite.utils.tls.TLSUtils;
|
import org.keycloak.testsuite.utils.tls.TLSUtils;
|
||||||
import org.keycloak.testsuite.utils.undertow.UndertowDeployerHelper;
|
import org.keycloak.testsuite.utils.undertow.UndertowDeployerHelper;
|
||||||
import org.keycloak.testsuite.utils.undertow.UndertowWarClassLoader;
|
import org.keycloak.testsuite.utils.undertow.UndertowWarClassLoader;
|
||||||
|
@ -99,7 +99,7 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
|
||||||
di.setDefaultServletConfig(new DefaultServletConfig(true));
|
di.setDefaultServletConfig(new DefaultServletConfig(true));
|
||||||
di.addWelcomePage("theme/keycloak/welcome/resources/index.html");
|
di.addWelcomePage("theme/keycloak/welcome/resources/index.html");
|
||||||
|
|
||||||
FilterInfo filter = Servlets.filter("SessionFilter", UndertowClientConnectionServletFilter.class);
|
FilterInfo filter = Servlets.filter("SessionFilter", UndertowRequestFilter.class);
|
||||||
di.addFilter(filter);
|
di.addFilter(filter);
|
||||||
di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
|
di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
|
||||||
filter.setAsyncSupported(true);
|
filter.setAsyncSupported(true);
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
|
||||||
private HashMap<String, Object> keycloakConfigPropertyOverridesMap;
|
private HashMap<String, Object> keycloakConfigPropertyOverridesMap;
|
||||||
private String profile;
|
private String profile;
|
||||||
private String javaOpts;
|
private String javaOpts;
|
||||||
|
private boolean reaugmentBeforeStart;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws ConfigurationException {
|
public void validate() throws ConfigurationException {
|
||||||
|
@ -136,4 +137,12 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
|
||||||
public String getJavaOpts() {
|
public String getJavaOpts() {
|
||||||
return javaOpts;
|
return javaOpts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isReaugmentBeforeStart() {
|
||||||
|
return reaugmentBeforeStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReaugmentBeforeStart(boolean reaugmentBeforeStart) {
|
||||||
|
this.reaugmentBeforeStart = reaugmentBeforeStart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,19 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
||||||
FileUtils.deleteDirectory(configuration.getProvidersPath().resolve("data").toFile());
|
FileUtils.deleteDirectory(configuration.getProvidersPath().resolve("data").toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configuration.isReaugmentBeforeStart()) {
|
||||||
|
ProcessBuilder reaugment = new ProcessBuilder("./kc.sh", "config");
|
||||||
|
|
||||||
|
reaugment.directory(wrkDir).inheritIO();
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.infof("Re-building the server with the new configuration");
|
||||||
|
reaugment.start().waitFor(10, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException("Timeout while waiting for re-augmentation", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return builder.start();
|
return builder.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class DatasetTest extends EntityTest<Dataset> implements Loggable {
|
||||||
};
|
};
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
mapper.setSerializationInclusion(Include.NON_NULL);
|
mapper.setSerializationInclusion(Include.NON_NULL);
|
||||||
Map<String, Object> map = mapper.convertValue(realm, typeRef);
|
Map<String, Object> map = (Map<String, Object>) mapper.convertValue(realm, typeRef);
|
||||||
map.put("index", 1000);
|
map.put("index", 1000);
|
||||||
|
|
||||||
logger().info("MAP:");
|
logger().info("MAP:");
|
||||||
|
|
|
@ -22,9 +22,7 @@ import io.undertow.servlet.Servlets;
|
||||||
import io.undertow.servlet.api.DefaultServletConfig;
|
import io.undertow.servlet.api.DefaultServletConfig;
|
||||||
import io.undertow.servlet.api.DeploymentInfo;
|
import io.undertow.servlet.api.DeploymentInfo;
|
||||||
import io.undertow.servlet.api.FilterInfo;
|
import io.undertow.servlet.api.FilterInfo;
|
||||||
import io.undertow.servlet.api.ServletInfo;
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher;
|
|
||||||
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
|
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
|
||||||
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||||
|
@ -405,7 +403,7 @@ public class KeycloakServer {
|
||||||
// KEYCLOAK-14178
|
// KEYCLOAK-14178
|
||||||
deployment.setProperty(ResteasyContextParameters.RESTEASY_DISABLE_HTML_SANITIZER, true);
|
deployment.setProperty(ResteasyContextParameters.RESTEASY_DISABLE_HTML_SANITIZER, true);
|
||||||
|
|
||||||
FilterInfo filter = Servlets.filter("SessionFilter", UndertowClientConnectionServletFilter.class);
|
FilterInfo filter = Servlets.filter("SessionFilter", UndertowRequestFilter.class);
|
||||||
filter.setAsyncSupported(true);
|
filter.setAsyncSupported(true);
|
||||||
|
|
||||||
di.addFilter(filter);
|
di.addFilter(filter);
|
||||||
|
|
|
@ -27,9 +27,9 @@ import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.services.filters.AbstractClientConnectionFilter;
|
import org.keycloak.services.filters.AbstractRequestFilter;
|
||||||
|
|
||||||
public class UndertowClientConnectionServletFilter extends AbstractClientConnectionFilter implements Filter {
|
public class UndertowRequestFilter extends AbstractRequestFilter implements Filter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
|
@ -26,9 +26,9 @@ import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.services.filters.AbstractClientConnectionFilter;
|
import org.keycloak.services.filters.AbstractRequestFilter;
|
||||||
|
|
||||||
public class WildFlyClientConnectionServletFilter extends AbstractClientConnectionFilter implements Filter {
|
public class WildFlyRequestFilter extends AbstractRequestFilter implements Filter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
Loading…
Reference in a new issue