Skip to content

Commit

Permalink
Finalize Dev Services for OIDC
Browse files Browse the repository at this point in the history
  • Loading branch information
michalvavrik committed Jan 9, 2025
1 parent 60c7df0 commit 00c9a80
Show file tree
Hide file tree
Showing 31 changed files with 1,869 additions and 776 deletions.
2 changes: 1 addition & 1 deletion .github/native-tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
{
"category": "Security2",
"timeout": 75,
"test-modules": "oidc, oidc-code-flow, oidc-tenancy, oidc-client, oidc-client-reactive, oidc-token-propagation, oidc-wiremock, oidc-client-wiremock, oidc-wiremock-providers",
"test-modules": "oidc, oidc-code-flow, oidc-tenancy, oidc-client, oidc-client-reactive, oidc-token-propagation, oidc-wiremock, oidc-client-wiremock, oidc-wiremock-providers, oidc-dev-services",
"os-name": "ubuntu-latest"
},
{
Expand Down
5 changes: 5 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,11 @@
<artifactId>quarkus-devservices-keycloak</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-devservices-oidc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-flyway</artifactId>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 43 additions & 28 deletions docs/src/main/asciidoc/security-openid-connect-dev-services.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ The Dev Services for Keycloak feature starts a Keycloak container for both the d
It initializes them by registering the existing Keycloak realm or creating a new realm with the client and users required for you to start developing your Quarkus application secured by Keycloak immediately.
The container restarts when the `application.properties` or the realm file changes have been detected.

Additionally, xref:dev-ui.adoc[Dev UI] available at http://localhost:8080/q/dev[/q/dev] complements this feature with a Dev UI page, which helps to acquire the tokens from Keycloak and test your Quarkus application.
Additionally, xref:dev-ui.adoc[Dev UI] available at http://localhost:8080/q/dev-ui/extensions[/q/dev-ui/extensions] complements this feature with a Dev UI page, which helps to acquire the tokens from Keycloak and test your Quarkus application.

If `quarkus.oidc.auth-server-url` is already set, then a generic OpenID Connect Dev Console, which can be used with all OpenID Connect providers, is activated.
For more information, see <<dev-ui-all-oidc-providers,Dev UI for all OpenID Connect providers>>.

[[dev-services-for-keycloak]]
== Dev Services for Keycloak

Start your application without configuring `quarkus.oidc` properties in the `application.properties` file:
Expand Down Expand Up @@ -221,33 +222,6 @@ image::dev-ui-keycloak-sign-in-to-service.png[alt=Dev UI OpenID Connect Keycloak
Set a relative service endpoint path and click *Log in to your web application*.
You are redirected to Keycloak to enter a username and password in a new browser tab before you get a response from the Quarkus application.

In this case, the Dev UI is not very helpful because the Quarkus OIDC `web-app` application controls the authorization code flow and acquires the tokens.

To make Dev UI more helpful in supporting the development of OIDC `web-app` applications, consider setting profile-specific values for `quarkus.oidc.application-type`:

[source,properties]
----
%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=service
----

This profile ensures that all Dev UI options described in <<develop-service-applications,Developing service applications>> are available when your `web-app` application is run in dev mode.
The limitation of this approach is that both access and ID tokens returned with the code flow and acquired with Dev UI are sent to the endpoint as HTTP `Bearer` tokens - which does not work well if your endpoint requires the injection of `IdToken`.
However, it works as expected if your `web-app` application only uses the access token, for example, as a source of roles or to get `UserInfo`, even if it is assumed to be a `service` application in dev mode.

For dev mode, an even better option is to set the `application-type` property to `hybrid`:

[source,properties]
----
%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=hybrid
----

This type ensures that if you access the application from the browser in dev mode without the OIDC Dev UI, Quarkus OIDC also performs the authorization code flow as in the production mode.
The OIDC Dev UI is also more beneficial because hybrid applications can also accept the bearer access tokens.

=== Running the tests

You can run the tests against a Keycloak container started in a test mode in a xref:continuous-testing.adoc[Continuous Testing] mode.
Expand Down Expand Up @@ -406,6 +380,47 @@ This document refers to the `http://localhost:8080/q/dev-ui` Dev UI URL in sever
If you customize `quarkus.http.root-path` or `quarkus.http.non-application-root-path` properties, then replace `q` accordingly.
For more information, see the https://quarkus.io/blog/path-resolution-in-quarkus/[Path resolution in Quarkus] blog post.

== Dev Services for OIDC

When you work with Keycloak in production, <<dev-services-for-keycloak>> provides the best dev mode experience.
For other OpenID Connect providers, it is recommended to enable the Dev Services for OIDC like in the example below:

[source,properties]
----
quarkus.oidc.devservices.enabled=true
----

NOTE: the Dev Services for OIDC are enabled by default if Docker and Podman are not available.

Once enabled, Quarkus starts a new OIDC server that supports most common OpenID Connect operations.
You can confirm in your console that the OIDC server started, you will see output similar to the following:

[source,shell]
----
2025-01-08 20:50:20,900 INFO [io.qua.dev.oid.OidcDevServicesProcessor] (build-16) Dev Services for OIDC started on http://localhost:38139
----

If you navigate to the <<dev-ui-all-oidc-providers>>, you can log into the OIDC server as builtin users `alice` or `bob`:

image::dev-ui-oidc-dev-svc-login-page.png[alt=Dev Services for OIDC builtin user login,role="center"]

This login page is also displayed if you navigate to authenticated request path during the development of the xref:security-oidc-code-flow-authentication.adoc[Quarkus OIDC web application].
As always, the default roles for `alice` are `admin` and `user`, while the roles for `bob` are just `user`.
You can configure those built-in roles if required:

[source,properties]
----
quarkus.oidc.devservices.roles.alice=root <1>
quarkus.oidc.devservices.roles.bob=guest
----
<1> Assign a `root` role to the user `alice`.

Another option is log in as a custom user with the username and roles of your choice:

image::dev-ui-oidc-dev-svc-login-for-custom-users.png[alt=Dev Services for OIDC custom user login,role="center"]

Whichever user you choose, no password is required.

== References

* xref:dev-ui.adoc[Dev UI]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ public interface KeycloakDevServicesConfig {
@WithDefault("true")
boolean enabled();

/**
* Use lightweight dev services instead of Keycloak
*/
@ConfigItem(defaultValue = "false")
public boolean lightweight;

/**
* The container image name for Dev Services providers.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ DevServicesResultBuildItem startKeycloakContainer(
DevServicesConfig devServicesConfig, DockerStatusBuildItem dockerStatusBuildItem) {

if (devSvcRequiredMarkerItems.isEmpty()
|| linuxContainersNotAvailable(dockerStatusBuildItem, devSvcRequiredMarkerItems)) {
|| linuxContainersNotAvailable(dockerStatusBuildItem, devSvcRequiredMarkerItems)
|| oidcDevServicesEnabled()) {
if (devService != null) {
closeDevService();
}
Expand Down Expand Up @@ -248,6 +249,10 @@ public void run() {
return devService.toBuildItem();
}

private static boolean oidcDevServicesEnabled() {
return ConfigProvider.getConfig().getOptionalValue("quarkus.oidc.devservices.enabled", boolean.class).orElse(false);
}

private static boolean linuxContainersNotAvailable(DockerStatusBuildItem dockerStatusBuildItem,
List<KeycloakDevServicesRequiredBuildItem> devSvcRequiredMarkerItems) {
if (dockerStatusBuildItem.isContainerRuntimeAvailable()) {
Expand Down
53 changes: 53 additions & 0 deletions extensions/devservices/oidc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-devservices-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-devservices-oidc</artifactId>
<name>Quarkus - DevServices - OIDC</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-devservices-common</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-jwt-build</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.quarkus.devservices.oidc;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigDocDefault;
import io.quarkus.runtime.annotations.ConfigDocMapKey;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;

/**
* OpenID Connect Dev Services configuration.
*/
@ConfigRoot
@ConfigMapping(prefix = "quarkus.oidc.devservices")
public interface OidcDevServicesConfig {

/**
* Use OpenID Connect Dev Services instead of Keycloak.
*/
@ConfigDocDefault("Enabled when Docker and Podman are not available")
Optional<Boolean> enabled();

/**
* A map of roles for OIDC identity provider users.
* <p>
* If empty, default roles are assigned: `alice` receives `admin` and `user` roles, while other users receive
* `user` role.
* This map is used for role creation when no realm file is found at the `realm-path`.
*/
@ConfigDocMapKey("role-name")
Map<String, List<String>> roles();

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package io.quarkus.oidc.deployment.devservices.keycloak;
package io.quarkus.devservices.oidc;

import java.util.Map;

import io.quarkus.builder.item.SimpleBuildItem;

public final class LightweightDevServicesConfigBuildItem extends SimpleBuildItem {
/**
* OIDC Dev Services configuration properties.
*/
public final class OidcDevServicesConfigBuildItem extends SimpleBuildItem {

private final Map<String, String> config;

public LightweightDevServicesConfigBuildItem(Map<String, String> config) {
OidcDevServicesConfigBuildItem(Map<String, String> config) {
this.config = config;
}

public Map<String, String> getConfig() {
return config;
}

}
Loading

0 comments on commit 00c9a80

Please sign in to comment.