[KEYCLOAK-17866] - Upgrade to Quarkus v2
This commit is contained in:
parent
47484c1aed
commit
aa018295c4
32 changed files with 339 additions and 132 deletions
21
.github/workflows/ci.yml
vendored
21
.github/workflows/ci.yml
vendored
|
@ -2,6 +2,9 @@ name: Keycloak CI
|
|||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DEFAULT_JDK_VERSION: 11
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
|
@ -10,7 +13,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
- name: Cache Maven packages
|
||||
|
@ -24,7 +27,7 @@ jobs:
|
|||
|
||||
- name: Build Keycloak
|
||||
run: |
|
||||
mvn clean install -nsu -B -e -DskipTests -Pquarkus,distribution
|
||||
mvn clean install -nsu -B -e -DskipTests -Pdistribution
|
||||
mvn clean install -nsu -B -e -f testsuite/integration-arquillian/servers/auth-server -Pauth-server-quarkus
|
||||
mvn clean install -nsu -B -e -f testsuite/integration-arquillian/servers/auth-server -Pauth-server-wildfly
|
||||
mvn clean install -nsu -B -e -f testsuite/integration-arquillian/servers/auth-server -Pauth-server-undertow
|
||||
|
@ -53,7 +56,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
- name: Cache Maven packages
|
||||
|
@ -94,7 +97,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
- name: Cache Maven packages
|
||||
|
@ -160,7 +163,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
|
||||
|
@ -224,7 +227,7 @@ jobs:
|
|||
- uses: actions/setup-java@v1
|
||||
if: ${{ github.event_name != 'pull_request' || env.GIT_DIFF != 0 }}
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
if: ${{ github.event_name != 'pull_request' || env.GIT_DIFF != 0 }}
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
|
@ -263,7 +266,7 @@ jobs:
|
|||
- uses: actions/setup-java@v1
|
||||
if: ${{ github.event_name != 'pull_request' || env.GIT_DIFF != 0 }}
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
if: ${{ github.event_name != 'pull_request' || env.GIT_DIFF != 0 }}
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
|
@ -336,7 +339,7 @@ jobs:
|
|||
name: keycloak-artifacts.zip
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: ${{ env.DEFAULT_JDK_VERSION }}
|
||||
- name: Update maven settings
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
- name: Run Quarkus cluster tests
|
||||
|
@ -374,7 +377,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
java-version: 8
|
||||
- name: Update maven settings
|
||||
run: mkdir -p ~/.m2 ; cp .github/settings.xml ~/.m2/
|
||||
- name: Cache Maven packages
|
||||
|
|
|
@ -78,8 +78,9 @@
|
|||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>community</id>
|
||||
<id>quarkus</id>
|
||||
<activation>
|
||||
<jdk>[11,)</jdk>
|
||||
<property>
|
||||
<name>!product</name>
|
||||
</property>
|
||||
|
|
|
@ -51,6 +51,10 @@ Classes from `org.keycloak.testsuite.*` packages aren't suitable to be used in p
|
|||
|
||||
---
|
||||
|
||||
### Building Quarkus Distribution
|
||||
|
||||
Please, take a look at this [documentation](../quarkus/README.md).
|
||||
|
||||
## Starting Keycloak
|
||||
|
||||
To start Keycloak during development first build as specified above, then run:
|
||||
|
|
10
pom.xml
10
pom.xml
|
@ -1897,6 +1897,16 @@
|
|||
<ee.maven.version>${wildfly.version}</ee.maven.version>
|
||||
<product.filename.version>${project.version}</product.filename.version>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>quarkus</id>
|
||||
<activation>
|
||||
<jdk>[11,)</jdk>
|
||||
<property>
|
||||
<name>!product</name>
|
||||
</property>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>quarkus</module>
|
||||
</modules>
|
||||
|
|
|
@ -13,12 +13,22 @@ The module holds the codebase to run Keycloak on top of [Quarkus](https://quarku
|
|||
├── The server itself, only responsible for generating the server artifacts
|
||||
```
|
||||
|
||||
## Activating the Module
|
||||
|
||||
When build from the project root directory, this module is only enabled if the installed JDK is 11 or newer.
|
||||
|
||||
## Building
|
||||
|
||||
Ensure you have JDK 11 (or newer) installed.
|
||||
|
||||
To build the module and produce the artifacts to run a server:
|
||||
|
||||
mvn -f ../pom.xml clean install -DskipTestsuite -DskipExamples -DskipTests
|
||||
|
||||
If you already built Keycloak artifacts using JDK 8, you should be able to skip the previous step and just build this module as follows:
|
||||
|
||||
mvn clean install
|
||||
|
||||
### Building the Distribution
|
||||
|
||||
To build the module as well as the distribution packages:
|
||||
|
@ -27,12 +37,16 @@ To build the module as well as the distribution packages:
|
|||
|
||||
The distribution packages (ZIP and TAR) should be available at [../distribution/server-x-dist](../distribution/server-x-dist/target).
|
||||
|
||||
Alternatively, you can also build the distribution directly by running the following command:
|
||||
|
||||
mvn -f ../distribution/server-x-dist/pom.xml clean install
|
||||
|
||||
## Running
|
||||
|
||||
By default, the HTTP port is disabled and you need to provide the key material to configure HTTPS. If you want to enable
|
||||
the HTTP port, run the server in development mode as follows:
|
||||
|
||||
java -jar server/target/lib/quarkus-run.jar --profile=dev
|
||||
java -jar server/target/lib/quarkus-run.jar start-dev
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -40,17 +54,19 @@ the HTTP port, run the server in development mode as follows:
|
|||
|
||||
To run the server in development mode:
|
||||
|
||||
cd server
|
||||
mvn compile quarkus:dev
|
||||
mvn -f server/pom.xml compile quarkus:dev
|
||||
|
||||
You should be able to attach your debugger to port `5005`.
|
||||
|
||||
Changes to files such as `server/src/main/resources` or `server/src/main/resources/META-INF/keycloak.properties` should
|
||||
be recognized automatically when running in development mode.
|
||||
For debugging the build steps, you can suspend the JVM by running:
|
||||
|
||||
However, considering that there is no real code in the `server` module (but from `runtime` and its dependencies), changes you make to
|
||||
dependencies (e.g: services, model, etc) won't be reflected into the running server. However, you can still leverage the
|
||||
hot reload capabilities from your IDE to make changes at runtime.
|
||||
mvn -f server/pom.xml -Dsuspend=true compile quarkus:dev
|
||||
|
||||
NOTE: We need to improve DevX and figure out why changes to dependencies are not being recognized when running tests or running
|
||||
Quarkus Dev Mode.
|
||||
When running using `quarkus:dev` you should be able to do live coding whenever code changes within the `server` module. Changes you make to transient dependencies from the server extension (e.g: services, model, etc) won't be reflected into the running server. However, you can still leverage the hot swapping capabilities from your IDE to make changes at runtime.
|
||||
|
||||
NOTE: Although still very handy during development, there are some limitations when running in dev mode that
|
||||
blocks us to leverage all the capabilities from Quarkus dev mode. For instance, hot-reload of transient dependencies from the server extension (e.g.: keycloak-* dependencies) does not work. More improvements should be expected to improve the experience.
|
||||
|
||||
NOTE: When developing custom providers, you should be able to benefit from live coding as long as you keep changes within the `server` module.
|
||||
|
||||
Alternatively, you can run the server in development mode from your IDE. For that, run the `org.keycloak.quarkus._private.IDELauncher` main class.
|
|
@ -58,10 +58,6 @@
|
|||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-jdbc-mysql-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-vertx-web-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-bootstrap-core</artifactId>
|
||||
|
|
|
@ -50,8 +50,11 @@ import java.util.jar.JarFile;
|
|||
import io.quarkus.deployment.IsDevelopment;
|
||||
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
|
||||
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
|
||||
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
|
||||
import io.quarkus.deployment.builditem.StaticInitConfigSourceProviderBuildItem;
|
||||
import io.quarkus.hibernate.orm.deployment.HibernateOrmConfig;
|
||||
import io.quarkus.resteasy.server.common.deployment.ResteasyDeploymentCustomizerBuildItem;
|
||||
import io.quarkus.runtime.LaunchMode;
|
||||
import io.quarkus.smallrye.health.runtime.SmallRyeHealthHandler;
|
||||
import io.quarkus.vertx.http.deployment.RouteBuildItem;
|
||||
import io.vertx.core.Handler;
|
||||
|
@ -85,6 +88,7 @@ import org.keycloak.provider.ProviderFactory;
|
|||
import org.keycloak.provider.ProviderManager;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.provider.quarkus.QuarkusRequestFilter;
|
||||
import org.keycloak.provider.quarkus.dev.QuarkusDevRequestFilter;
|
||||
import org.keycloak.quarkus.KeycloakRecorder;
|
||||
|
||||
import io.quarkus.deployment.annotations.BuildProducer;
|
||||
|
@ -191,6 +195,16 @@ class KeycloakProcessor {
|
|||
recorder.configSessionFactory(factories, defaultProviders, preConfiguredProviders, Environment.isRebuild());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the custom {@link org.eclipse.microprofile.config.spi.ConfigSource} implementations.
|
||||
*
|
||||
* @param configSources
|
||||
*/
|
||||
@BuildStep
|
||||
void configureConfigSources(BuildProducer<StaticInitConfigSourceProviderBuildItem> configSources) {
|
||||
configSources.produce(new StaticInitConfigSourceProviderBuildItem(KeycloakConfigSourceProvider.class.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make the build time configuration available at runtime so that the server can run without having to specify some of
|
||||
* the properties again.
|
||||
|
@ -253,8 +267,15 @@ class KeycloakProcessor {
|
|||
}
|
||||
|
||||
@BuildStep
|
||||
void initializeFilter(BuildProducer<FilterBuildItem> filters) {
|
||||
filters.produce(new FilterBuildItem(new QuarkusRequestFilter(),FilterBuildItem.AUTHORIZATION - 10));
|
||||
void initializeFilter(BuildProducer<FilterBuildItem> filters, LaunchModeBuildItem launchModeBuildItem) {
|
||||
QuarkusRequestFilter filter = new QuarkusRequestFilter();
|
||||
LaunchMode launchMode = launchModeBuildItem.getLaunchMode();
|
||||
|
||||
if (launchMode.isDevOrTest()) {
|
||||
filter = new QuarkusDevRequestFilter();
|
||||
}
|
||||
|
||||
filters.produce(new FilterBuildItem(filter,FilterBuildItem.AUTHORIZATION - 10));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -283,10 +304,10 @@ class KeycloakProcessor {
|
|||
metricsHandler = new NotFoundHandler();
|
||||
}
|
||||
|
||||
routes.produce(new RouteBuildItem(DEFAULT_HEALTH_ENDPOINT, healthHandler));
|
||||
routes.produce(new RouteBuildItem(DEFAULT_HEALTH_ENDPOINT.concat("/live"), healthHandler));
|
||||
routes.produce(new RouteBuildItem(DEFAULT_HEALTH_ENDPOINT.concat("/ready"), healthHandler));
|
||||
routes.produce(new RouteBuildItem(KeycloakMetricsHandler.DEFAULT_METRICS_ENDPOINT, metricsHandler));
|
||||
routes.produce(RouteBuildItem.builder().route(DEFAULT_HEALTH_ENDPOINT).handler(healthHandler).build());
|
||||
routes.produce(RouteBuildItem.builder().route(DEFAULT_HEALTH_ENDPOINT.concat("/live")).handler(healthHandler).build());
|
||||
routes.produce(RouteBuildItem.builder().route(DEFAULT_HEALTH_ENDPOINT.concat("/ready")).handler(healthHandler).build());
|
||||
routes.produce(RouteBuildItem.builder().route(KeycloakMetricsHandler.DEFAULT_METRICS_ENDPOINT).handler(metricsHandler).build());
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
|
@ -310,7 +331,7 @@ class KeycloakProcessor {
|
|||
|
||||
private Map<Spi, Map<Class<? extends Provider>, Map<String, ProviderFactory>>> loadFactories(
|
||||
Map<String, ProviderFactory> preConfiguredProviders) {
|
||||
loadConfig();
|
||||
Config.init(new MicroProfileConfigProvider());
|
||||
BuildClassLoader providerClassLoader = new BuildClassLoader();
|
||||
ProviderManager pm = new ProviderManager(KeycloakDeploymentInfo.create().services(), providerClassLoader);
|
||||
Map<Spi, Map<Class<? extends Provider>, Map<String, ProviderFactory>>> factories = new HashMap<>();
|
||||
|
@ -485,18 +506,6 @@ class KeycloakProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
protected void loadConfig() {
|
||||
ServiceLoader<ConfigProviderFactory> loader = ServiceLoader.load(ConfigProviderFactory.class, KeycloakApplication.class.getClassLoader());
|
||||
|
||||
try {
|
||||
ConfigProviderFactory factory = loader.iterator().next();
|
||||
logger.debugv("ConfigProvider: {0}", factory.getClass().getName());
|
||||
Config.init(factory.create().orElseThrow(() -> new RuntimeException("Failed to load Keycloak configuration")));
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new RuntimeException("No valid ConfigProvider found");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMetricsEnabled() {
|
||||
return Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("metrics.enabled")).orElse(false);
|
||||
}
|
||||
|
|
|
@ -3,3 +3,4 @@ quarkus.application.name=Keycloak
|
|||
quarkus.banner.enabled=false
|
||||
|
||||
quarkus.resteasy.ignore-application-classes=true
|
||||
quarkus.arc.ignored-split-packages=org.keycloak.*
|
120
quarkus/pom.xml
120
quarkus/pom.xml
|
@ -31,21 +31,37 @@
|
|||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<quarkus.version>1.13.3.Final</quarkus.version>
|
||||
<resteasy.version>4.5.9.Final</resteasy.version>
|
||||
<jackson.version>2.12.1</jackson.version>
|
||||
<!-- Quarkus version -->
|
||||
<quarkus.version>2.2.2.Final</quarkus.version>
|
||||
|
||||
<!--
|
||||
Override versions based on Quarkus dependencies.
|
||||
Make sure to update these dependencies when Quarkus version changes.
|
||||
-->
|
||||
<resteasy.version>4.7.0.Final</resteasy.version>
|
||||
<jackson.version>2.12.5</jackson.version>
|
||||
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
||||
<hibernate.version>5.4.29.Final</hibernate.version>
|
||||
<mysql.driver.version>8.0.24</mysql.driver.version>
|
||||
<postgresql.driver.version>42.2.20</postgresql.driver.version>
|
||||
<picocli.version>4.6.1</picocli.version>
|
||||
<snakeyaml.version>1.28</snakeyaml.version>
|
||||
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
|
||||
<wildfly.common.format.version>1.5.4.Final-format-001</wildfly.common.format.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<hibernate.core.version>5.6.0.Beta1</hibernate.core.version>
|
||||
<mysql.driver.version>8.0.26</mysql.driver.version>
|
||||
<postgresql.version>42.2.23</postgresql.version>
|
||||
<microprofile-metrics-api.version>3.0</microprofile-metrics-api.version>
|
||||
<wildfly.common.version>1.5.4.Final-format-001</wildfly.common.version>
|
||||
|
||||
<!--
|
||||
Java EE dependencies. Not available from JDK 11+.
|
||||
The dependencies and their versions are the same used by Wildfly distribution.
|
||||
-->
|
||||
<org.jboss.spec.javax.xml.bind.jboss-jaxb-api_2.3_spec.version>2.0.1.Final</org.jboss.spec.javax.xml.bind.jboss-jaxb-api_2.3_spec.version>
|
||||
<sun.saaj-impl.version>1.4.1.SP1</sun.saaj-impl.version>
|
||||
<org.jvnet.staxex.version>1.8.3</org.jvnet.staxex.version>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<noDeps>true</noDeps>
|
||||
<maven.compiler.plugin.version>3.8.1</maven.compiler.plugin.version>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
|
||||
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -58,12 +74,7 @@
|
|||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Override the dependencies below to use the versions used by Quarkus -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>${hibernate.version}</version>
|
||||
</dependency>
|
||||
<!-- Override the dependencies below to use the versions used by Keycloak -->
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-core</artifactId>
|
||||
|
@ -79,45 +90,74 @@
|
|||
<artifactId>infinispan-client-hotrod</artifactId>
|
||||
<version>${infinispan.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependencies removed from JDK 11 and in compliance with those used by Wildfly. -->
|
||||
<dependency>
|
||||
<groupId>org.wildfly.common</groupId>
|
||||
<artifactId>wildfly-common</artifactId>
|
||||
<version>${wildfly.common.format.version}</version>
|
||||
<groupId>org.jboss.spec.javax.xml.bind</groupId>
|
||||
<artifactId>jboss-jaxb-api_2.3_spec</artifactId>
|
||||
<version>${org.jboss.spec.javax.xml.bind.jboss-jaxb-api_2.3_spec.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.messaging.saaj</groupId>
|
||||
<artifactId>saaj-impl</artifactId>
|
||||
<version>${sun.saaj-impl.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
<groupId>javax.xml.soap</groupId>
|
||||
<artifactId>saaj-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jvnet.mimepull</groupId>
|
||||
<artifactId>mimepull</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jvnet.staxex</groupId>
|
||||
<artifactId>stax-ex</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.driver.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.driver.version}</version>
|
||||
<groupId>org.jvnet.staxex</groupId>
|
||||
<artifactId>stax-ex</artifactId>
|
||||
<version>${org.jvnet.staxex.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<groupId>javax.xml.stream</groupId>
|
||||
<artifactId>stax-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler.plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<modules>
|
||||
<module>deployment</module>
|
||||
<module>runtime</module>
|
||||
<module>deployment</module>
|
||||
<module>server</module>
|
||||
</modules>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jboss-public-repository</id>
|
||||
<name>Jboss Public</name>
|
||||
<url>https://repository.jboss.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
<name>Keycloak Quarkus Server Extension</name>
|
||||
<artifactId>keycloak-quarkus-server</artifactId>
|
||||
<description>Keycloak Server</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Quarkus -->
|
||||
|
@ -76,7 +77,6 @@
|
|||
<dependency>
|
||||
<groupId>info.picocli</groupId>
|
||||
<artifactId>picocli</artifactId>
|
||||
<version>${picocli.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Keycloak -->
|
||||
|
@ -461,6 +461,19 @@
|
|||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-jboss-marshalling</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.xml.bind</groupId>
|
||||
<artifactId>jboss-jaxb-api_2.3_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.messaging.saaj</groupId>
|
||||
<artifactId>saaj-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.staxex</groupId>
|
||||
<artifactId>stax-ex</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
|
|
@ -22,6 +22,7 @@ import static org.keycloak.cli.Picocli.error;
|
|||
import static org.keycloak.cli.Picocli.getCliArgs;
|
||||
import static org.keycloak.cli.Picocli.parseConfigArgs;
|
||||
import static org.keycloak.util.Environment.getProfileOrDefault;
|
||||
import static org.keycloak.util.Environment.isDevMode;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
|
@ -51,8 +52,11 @@ public class KeycloakMain {
|
|||
if (cliArgs.length == 0) {
|
||||
// no arguments, just start the server
|
||||
start(Collections.emptyList(), new PrintWriter(System.err));
|
||||
if (!isDevMode()) {
|
||||
System.exit(CommandLine.ExitCode.OK);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// parse arguments and execute any of the configured commands
|
||||
parseAndRun(cliArgs);
|
||||
|
@ -63,9 +67,20 @@ public class KeycloakMain {
|
|||
}
|
||||
|
||||
private static void start(List<String> cliArgs, PrintWriter errorWriter) {
|
||||
Quarkus.run(null, (integer, throwable) -> {
|
||||
error(cliArgs, errorWriter, String.format("Failed to start server using profile (%s).", getProfileOrDefault("none")), throwable.getCause());
|
||||
try {
|
||||
Quarkus.run(null, (integer, cause) -> {
|
||||
if (cause != null) {
|
||||
error(cliArgs, errorWriter,
|
||||
String.format("Failed to start server using profile (%s)", getProfileOrDefault("none")),
|
||||
cause.getCause());
|
||||
}
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
error(cliArgs, errorWriter,
|
||||
String.format("Unexpected error when starting the server using profile (%s)", getProfileOrDefault("none")),
|
||||
cause.getCause());
|
||||
}
|
||||
|
||||
Quarkus.waitForExit();
|
||||
}
|
||||
|
||||
|
@ -96,6 +111,10 @@ public class KeycloakMain {
|
|||
System.exit(cmd.getCommandSpec().exitCodeOnExecutionException());
|
||||
}
|
||||
|
||||
System.exit(cmd.execute(cliArgs.toArray(new String[cliArgs.size()])));
|
||||
int exitCode = cmd.execute(cliArgs.toArray(new String[cliArgs.size()]));
|
||||
|
||||
if (!isDevMode()) {
|
||||
System.exit(exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,12 @@ public final class ShowConfigCommand {
|
|||
@Override
|
||||
public boolean test(String s) {
|
||||
ConfigValue configValue = getConfigValue(s);
|
||||
return configValue.getConfigSourceName().equals(PersistedConfigSource.NAME);
|
||||
|
||||
if (configValue == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return PersistedConfigSource.NAME.equals(configValue.getConfigSourceName());
|
||||
}
|
||||
})
|
||||
.filter(property -> filterByGroup(property))
|
||||
|
|
|
@ -105,7 +105,7 @@ public class KeycloakConfigSourceProvider implements ConfigSourceProvider {
|
|||
String homeDir = Environment.getHomeDir();
|
||||
|
||||
if (homeDir == null) {
|
||||
return Paths.get(Platform.getPlatform().getTmpDirectory().toString(), PersistedConfigSource.KEYCLOAK_PROPERTIES);
|
||||
return Paths.get(System.getProperty("java.io.tmpdir"), PersistedConfigSource.KEYCLOAK_PROPERTIES);
|
||||
}
|
||||
|
||||
return Paths.get(homeDir, "conf", PersistedConfigSource.KEYCLOAK_PROPERTIES);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.eclipse.microprofile.config.spi.ConfigSource;
|
||||
|
@ -44,6 +45,11 @@ public class SysPropConfigSource implements ConfigSource {
|
|||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPropertyNames() {
|
||||
return properties.keySet();
|
||||
}
|
||||
|
||||
public String getValue(final String propertyName) {
|
||||
return System.getProperty(propertyName);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.keycloak.Config;
|
|||
import org.keycloak.ServerStartupError;
|
||||
import org.keycloak.common.Version;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProvider;
|
||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||
import org.keycloak.exportimport.ExportImportManager;
|
||||
|
@ -152,14 +153,14 @@ public final class QuarkusJpaConnectionProviderFactory implements JpaConnectionP
|
|||
session.close();
|
||||
}
|
||||
|
||||
if (initSchema) {
|
||||
if (initSchema || ExportImportConfig.ACTION_EXPORT.equals(ExportImportConfig.getAction())) {
|
||||
runJobInTransaction(factory, this::initSchemaOrExport);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
SessionFactoryImpl entityManagerFactory = SessionFactoryImpl.class.cast(emf);
|
||||
SessionFactoryImpl entityManagerFactory = emf.unwrap(SessionFactoryImpl.class);
|
||||
|
||||
try {
|
||||
return entityManagerFactory.getJdbcServices().getBootstrapJdbcConnectionAccess().obtainConnection();
|
||||
|
|
|
@ -31,7 +31,13 @@ public class ResteasyVertxProvider implements ResteasyProvider {
|
|||
R data = ResteasyContext.getContextData(type);
|
||||
|
||||
if (data == null) {
|
||||
return (R) ResteasyContext.getContextData(RoutingContext.class).data().get(type.getName());
|
||||
RoutingContext contextData = ResteasyContext.getContextData(RoutingContext.class);
|
||||
|
||||
if (contextData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (R) contextData.data().get(type.getName());
|
||||
}
|
||||
|
||||
return data;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.provider.quarkus.dev;
|
||||
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import org.keycloak.provider.quarkus.QuarkusRequestFilter;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class QuarkusDevRequestFilter extends QuarkusRequestFilter {
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext context) {
|
||||
if (context.request().uri().startsWith("/q/")) {
|
||||
// do not go through Keycloak request filter if serving Quarkus resources such as dev console
|
||||
context.next();
|
||||
return;
|
||||
}
|
||||
super.handle(context);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ package org.keycloak.quarkus;
|
|||
|
||||
import static org.keycloak.configuration.Configuration.getBuiltTimeProperty;
|
||||
import static org.keycloak.configuration.Configuration.getConfig;
|
||||
import static org.keycloak.configuration.Configuration.getConfigValue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -135,17 +136,21 @@ public class KeycloakRecorder {
|
|||
if (!StreamSupport.stream(getConfig().getPropertyNames().spliterator(), false)
|
||||
.filter(new Predicate<String>() {
|
||||
@Override
|
||||
public boolean test(String s) {
|
||||
ConfigValue configValue = getConfig().getConfigValue(s);
|
||||
public boolean test(String propertyName) {
|
||||
ConfigValue configValue = getConfigValue(propertyName);
|
||||
|
||||
return configValue.getConfigSourceName().equals(PersistedConfigSource.NAME);
|
||||
if (configValue == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return PersistedConfigSource.NAME.equals(configValue.getSourceName());
|
||||
}
|
||||
})
|
||||
.anyMatch(new Predicate<String>() {
|
||||
@Override
|
||||
public boolean test(String s) {
|
||||
public boolean test(String propertyName) {
|
||||
return PropertyMappers.canonicalFormat(finalPropertyName)
|
||||
.equalsIgnoreCase(PropertyMappers.canonicalFormat(s));
|
||||
.equalsIgnoreCase(PropertyMappers.canonicalFormat(propertyName));
|
||||
}
|
||||
})) {
|
||||
String prop = "--" + cliNameFormat.substring(3) + "=" + value.getValue();
|
||||
|
|
|
@ -59,7 +59,7 @@ public class KeycloakReadyHealthCheck extends DataSourceHealthCheck {
|
|||
long invalidCount = agroalDataSource.getMetrics().invalidCount();
|
||||
if (activeCount < 1 || invalidCount > 0) {
|
||||
HealthCheckResponse activeCheckResult = super.call();
|
||||
if (activeCheckResult.getState() == HealthCheckResponse.State.DOWN) {
|
||||
if (activeCheckResult.getStatus() == HealthCheckResponse.Status.DOWN) {
|
||||
builder.down();
|
||||
Instant failingTime = failingSince.updateAndGet(this::createInstanceIfNeeded);
|
||||
builder.withData("Failing since", DATE_FORMATTER.format(failingTime));
|
||||
|
|
|
@ -19,6 +19,8 @@ package org.keycloak.util;
|
|||
|
||||
import java.util.Optional;
|
||||
|
||||
import io.quarkus.runtime.LaunchMode;
|
||||
import io.quarkus.runtime.configuration.ProfileManager;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.keycloak.configuration.Configuration;
|
||||
|
||||
|
@ -80,7 +82,12 @@ public final class Environment {
|
|||
}
|
||||
|
||||
public static boolean isDevMode() {
|
||||
return "dev".equalsIgnoreCase(getProfile());
|
||||
if ("dev".equalsIgnoreCase(getProfile())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if running in quarkus:dev mode
|
||||
return ProfileManager.getLaunchMode() == LaunchMode.DEVELOPMENT;
|
||||
}
|
||||
|
||||
public static boolean isWindows() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
artifact: ${project.groupId}:${project.artifactId}:${project.version}
|
||||
name: "Keycloak"
|
||||
metadata:
|
||||
keywords:
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
|
||||
import io.quarkus.hibernate.orm.runtime.dialect.QuarkusH2Dialect;
|
||||
import io.quarkus.runtime.LaunchMode;
|
||||
import io.smallrye.config.SmallRyeConfig;
|
||||
import org.eclipse.microprofile.config.ConfigProvider;
|
||||
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
|
||||
|
@ -272,6 +273,6 @@ public class ConfigurationTest {
|
|||
|
||||
private SmallRyeConfig createConfig() {
|
||||
KeycloakConfigSourceProvider.reload();
|
||||
return ConfigUtils.configBuilder(true, true).build();
|
||||
return ConfigUtils.configBuilder(true, LaunchMode.NORMAL).build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,20 +19,6 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-quarkus-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- This dependency should not be here but due to the structure of the modules we need to make sure it is built
|
||||
before this module -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-quarkus-server-deployment</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package org.keycloak.quarkus._private;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import io.quarkus.runtime.Quarkus;
|
||||
import org.keycloak.util.Environment;
|
||||
|
||||
/**
|
||||
* <p>This main class should be used to start the server in dev mode for development purposes. By running this class,
|
||||
* developers should be able to mimic any server behavior and configuration as if they were using the CLI.
|
||||
*
|
||||
* <p>There are some limitations during development such as:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Transient dependencies from the keycloak server extension (runtime module) are not eligible for hot-reload</li>
|
||||
* <li>Code changes such as changing the structure of classes (e.g.: new/change methods) should still require a JVM restart</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Despite the limitations, it should be possible to debug the extension (e.g.: deployment steps) as well as perform changes at runtime
|
||||
* without having to restart the JVM.
|
||||
*
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class IDELauncher {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> devArgs = new ArrayList<>();
|
||||
|
||||
devArgs.addAll(Arrays.asList(args));
|
||||
|
||||
if (devArgs.isEmpty()) {
|
||||
devArgs.add("start-dev");
|
||||
}
|
||||
|
||||
Quarkus.run(devArgs.toArray(new String[devArgs.size()]));
|
||||
}
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
# Default and non-production grade database vendor
|
||||
db=h2-file
|
||||
db.username = sa
|
||||
db.password = keycloak
|
||||
|
||||
# Default, and insecure, and non-production grade configuration for the development profile
|
||||
%dev.http.enabled=true
|
||||
%dev.db.username = sa
|
||||
%dev.db.password = keycloak
|
||||
%dev.cluster=local
|
||||
%dev.spi.theme.cache-themes=false
|
||||
%dev.spi.theme.cache-templates=false
|
||||
%dev.spi.theme.static-max-age=-1
|
||||
# Insecure requests are disabled by default
|
||||
http.enabled=false
|
||||
|
||||
# Metrics and healthcheck are disabled by default
|
||||
metrics.enabled=false
|
||||
|
@ -16,6 +12,13 @@ metrics.enabled=false
|
|||
# Themes
|
||||
spi.theme.folder.dir=${kc.home.dir:}/themes
|
||||
|
||||
# Default, and insecure, and non-production grade configuration for the development profile
|
||||
%dev.http.enabled=true
|
||||
%dev.cluster=local
|
||||
%dev.spi.theme.cache-themes=false
|
||||
%dev.spi.theme.cache-templates=false
|
||||
%dev.spi.theme.static-max-age=-1
|
||||
|
||||
# Logging configuration. INFO is the default level for most of the categories
|
||||
#quarkus.log.level = DEBUG
|
||||
quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN
|
||||
|
|
|
@ -20,3 +20,6 @@ quarkus.transaction-manager.default-transaction-timeout=300
|
|||
# application classes are no longer supported by resteasy extension
|
||||
quarkus.resteasy.ignore-application-classes=true
|
||||
|
||||
# Ignore split packages for Keycloak related packages
|
||||
quarkus.arc.ignored-split-packages=org.keycloak.*
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>quarkus</id>
|
||||
<id>auth-server-quarkus</id>
|
||||
<modules>
|
||||
<module>quarkus</module>
|
||||
</modules>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<exec osfamily="unix" dir="${auth.server.home}/bin" executable="./kc.sh" failonerror="true">
|
||||
<arg value="config"/>
|
||||
<arg value="-Dquarkus.http.root-path=/auth"/>
|
||||
<arg value="--http-enabled=true"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
}
|
||||
|
||||
if (isReaugmentBeforeStart()) {
|
||||
List<String> commands = new ArrayList<>(Arrays.asList("./kc.sh", "config", "-Dquarkus.http.root-path=/auth"));
|
||||
List<String> commands = new ArrayList<>(Arrays.asList("./kc.sh", "config", "-Dquarkus.http.root-path=/auth", "--http-enabled=true"));
|
||||
|
||||
addAdditionalCommands(commands);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
/**
|
||||
* This class adapts the functionality from the old testsuite to make tests
|
||||
|
@ -100,4 +101,12 @@ public abstract class AbstractAdminTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
public static <T> T loadJson(InputStream is, TypeReference<T> type) {
|
||||
try {
|
||||
return JsonSerialization.readValue(is, type);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to parse json", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.testsuite.cli.admin;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -26,7 +27,7 @@ import static org.keycloak.testsuite.cli.KcAdmExec.execute;
|
|||
@AuthServerContainerExclude({AuthServer.REMOTE, AuthServer.QUARKUS})
|
||||
public class KcAdmSessionTest extends AbstractAdmCliTest {
|
||||
|
||||
static Class<? extends List<ObjectNode>> LIST_OF_JSON = new ArrayList<ObjectNode>() {}.getClass();
|
||||
static TypeReference<List<ObjectNode>> LIST_OF_JSON = new TypeReference<List<ObjectNode>>() {};
|
||||
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
|
|
|
@ -943,11 +943,12 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
|
||||
public static void setUserProfileConfiguration(RealmResource testRealm, String configuration) {
|
||||
Response r = testRealm.users().userProfile().update(configuration);
|
||||
try (Response r = testRealm.users().userProfile().update(configuration)) {
|
||||
if (r.getStatus() != 200) {
|
||||
Assert.fail("UserProfile Configuration not set due to error: " + r.readEntity(String.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static UserRepresentation getUser(RealmResource testRealm, String userId) {
|
||||
return testRealm.users().get(userId).toRepresentation();
|
||||
|
|
Loading…
Reference in a new issue