-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document how to test OIDC with DevServices and minor updates to quarkus-test-keycloak-server #19734
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -11,7 +11,8 @@ This guide covers the Dev Services for OpenId Connect (OIDC) Keycloak provider a | |||||
|
||||||
== Introduction | ||||||
|
||||||
Quarkus introduces an experimental `Dev Services For Keycloak` feature which is enabled by default when the `quarkus-oidc` extension is started in dev mode. It starts a Keycloak container and initializes it by registering the existing Keycloak realm or creating a new realm with the client and users for you to start developing your Quarkus application secured by Keycloak immediately. It will restart a container when the `application.properties` or the realm file changes have been detected. | ||||||
Quarkus introduces an experimental `Dev Services For Keycloak` feature which is enabled by default when the `quarkus-oidc` extension is started in dev mode with `mvn quarkus:dev` and when the integration tests are running in test mode, but only when no `quarkus.oidc.auth-server-url` property is configured. | ||||||
It starts a Keycloak container for both the dev and/or test modes and initializes them by registering the existing Keycloak realm or creating a new realm with the client and users for you to start developing your Quarkus application secured by Keycloak immediately. It will restart the container when the `application.properties` or the realm file changes have been detected. | ||||||
|
||||||
Additionally, link:dev-ui[Dev UI] available at http://localhost:8080/q/dev[/q/dev] supports this feature with a Keycloak specific page which helps to acquire the tokens from Keycloak and test your Quarkus application. | ||||||
|
||||||
|
@@ -28,20 +29,32 @@ $ mvn quarkus:dev | |||||
2021-06-04 16:22:47,629 INFO [🐳 .io/keycloak/keycloak:14.0.0]] (build-38) Container quay.io/keycloak/keycloak:14.0.0 is starting: 6469f6db9cec2c855fcc6c8db4273944cc9d69e8f6803a0b47eb2d5b8f5b94fd | ||||||
2021-06-04 16:22:47,643 INFO [org.tes.con.wai.str.HttpWaitStrategy] (build-38) /elastic_lovelace: Waiting for 60 seconds for URL: http://localhost:32812/auth (where port 32812 maps to container port 8080) | ||||||
2021-06-04 16:23:07,665 INFO [🐳 .io/keycloak/keycloak:14.0.0]] (build-38) Container quay.io/keycloak/keycloak:14.0.0 started in PT5.500489S | ||||||
2021-06-04 16:23:07,666 INFO [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-38) Dev Services for Keycloak started. | ||||||
... | ||||||
2021-06-04 16:23:11,155 INFO [io.quarkus] (Quarkus Main Thread) security-openid-connect-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 999-SNAPSHOT) started in 25.968s. Listening on: http://localhost:8080 | ||||||
2021-06-04 16:23:11,157 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. | ||||||
---- | ||||||
|
||||||
The `quay.io/keycloak/keycloak:14.0.0` Keycloak image is used by default to start a container. `quarkus.keycloak.devservices.image-name` can be used to change the Keycloak image used. | ||||||
|
||||||
Note that by default, `Dev Services for Keycloak` will not start a new container if it finds a container with a `quarkus-dev-service-keycloak` label and connect to it if this label's value matches the value of the `quarkus.keycloak.devservces.service-name` property (default value is `quarkus`). In such cases you will see a slighty different output: | ||||||
|
||||||
[source,shell] | ||||||
---- | ||||||
$ mvn quarkus:dev | ||||||
|
||||||
2021-08-27 18:42:43,530 INFO [io.qua.dev.com.ContainerLocator] (build-15) Dev Services container found: 48fee151a31ddfe32c39965be8f61108587b25ed2f66cdc18bb926d9e2e570c5 (quay.io/keycloak/keycloak:14.0.0). Connecting to: 0.0.0.0:32797. | ||||||
2021-08-27 18:42:43,600 INFO [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-15) Dev Services for Keycloak started. | ||||||
... | ||||||
---- | ||||||
|
||||||
Note that you can disable sharing the containers with `quarkus.keycloak.devservices.shared=false`. | ||||||
|
||||||
Now open the main link:http://localhost:8080/q/dev[Dev UI page] and you will see the `OpenId Connect Card` linking to a `Keycloak` page: | ||||||
|
||||||
image::dev-ui-oidc-keycloak-card.png[alt=Dev UI OpenId Connect Card,role="center"] | ||||||
|
||||||
Click on the `Provider: Keycloak` link and you will see a Keycloak page which will be presented slightly differently depending on how `Dev Services for Keycloak` feature has been configured. | ||||||
|
||||||
=== Testing Service Applications | ||||||
=== Developing Service Applications | ||||||
|
||||||
By default the Keycloak page can be used to support the development of a link:security-openid-connect[Quarkus OIDC service application]. | ||||||
|
||||||
|
@@ -63,8 +76,17 @@ Finally you can click a `Logged in` option if you'd like to log out and authenti | |||||
|
||||||
[NOTE] | ||||||
==== | ||||||
You may need to register a redirect URI for the authorization code flow initiated by Dev UI for Keycloak to work. | ||||||
Select a `Keycloak Admin` option in the right top corner, login as `admin:admin`, select the test realm and the client which Dev UI for Keycloak is configured with and add `http://localhost:8080/q/dev/io.quarkus.quarkus-oidc/provider` to `Valid Redirect URIs`. | ||||||
You may need to register a redirect URI for the authorization code flow initiated by Dev UI for Keycloak to work because Keycloak may enforce that the authenticated users are redirected only to the configured redirect URI. It is recommended to do in production to avoid the users being redirected to the wrong endpoints in case which might happen if the correct `redirect_uri` parameter in the authentication request URI has been manipulated. | ||||||
|
||||||
If Keycloak does enforce it then you will see an authentication error informing you that the `redirect_uri` value is wrong. | ||||||
|
||||||
In this case select the `Keycloak Admin` option in the right top corner, login as `admin:admin`, select the test realm and the client which Dev UI for Keycloak is configured with and add `http://localhost:8080/q/dev/io.quarkus.quarkus-oidc/provider` to `Valid Redirect URIs`. If you used `-Dquarkus.http.port` when starting Quarkus then change `8080` to the value of `quarkus.http.port`. | ||||||
|
||||||
If the container is shared between multiple applications running on different ports then you will need to register `redirect_uri` values for each of these applications. | ||||||
|
||||||
You can set the `redirect_uri` value to `*` only for the test purposes, especially when the containers are shared between multiple applications. | ||||||
|
||||||
`*` `redirect_uri` value is set by `Dev Services for Keycloak` when it creates a default realm, if no custom realm is imported. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should start by that maybe. Stating that if you just use the default, it's configured like that? |
||||||
==== | ||||||
|
||||||
==== Implicit Grant | ||||||
|
@@ -109,6 +131,13 @@ image::dev-ui-keycloak-sign-in-to-service.png[alt=Dev UI OpenId Connect Keycloak | |||||
|
||||||
Set a relative service endpoint path, click on `Sign In To Service` and you will be redirected to Keycloak to enter a username and password in a new browser tab and get a response from the Quarkus application. | ||||||
|
||||||
=== Running the tests | ||||||
|
||||||
You can run the tests against a Keycloak container started in a test mode in a link:continuous-testing[Continuous Testing] mode. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
But to be honest, I don't see the point of this sentence. |
||||||
|
||||||
It is also recommended to run the integration tests against Keycloak using `Dev Services for Keycloak`. | ||||||
Please see link:security-openid-connect#integration-testing-keycloak-devservices[Testing OpenId Connect Service Applications with Dev Services] and link:security-openid-connect-web-authentication#integration-testing-keycloak-devservices[Testing OpenId Connect WebApp Applications with Dev Services] for more information. | ||||||
|
||||||
=== Keycloak Initialization | ||||||
|
||||||
You do not need to configure `quarkus-oidc-keycloak` to start developing your Quarkus Keycloak `OIDC` applications with the only exception being that `quarkus.oidc.application-type=web-app` has to be set in `application.properties` to give the `Keycloak` page a hint it needs to show an option to `Sign In To Service`. | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -582,7 +582,7 @@ It applies to ID tokens but also to access tokens in a JWT format if the `web-ap | |||||
Please see link:security-openid-connect-client#token-propagation[Token Propagation] section about the Authorization Code Flow access token propagation to the downstream services. | ||||||
|
||||||
[[oidc-provider-client-authentication]] | ||||||
=== Oidc Provider Client Authentication | ||||||
== Oidc Provider Client Authentication | ||||||
|
||||||
`quarkus.oidc.runtime.OidcProviderClient` is used when a remote request to an OpenId Connect Provider has to be done. It has to authenticate to the OpenId Connect Provider when the authorization code has to be exchanged for the ID, access and refresh tokens, when the ID and access tokens have to be refreshed or introspected. | ||||||
|
||||||
|
@@ -784,10 +784,46 @@ Additionally, `OidcWiremockTestResource` set token issuer and audience to `https | |||||
|
||||||
`OidcWiremockTestResource` can be used to emulate all OpenId Connect providers. | ||||||
|
||||||
[[integration-testing-keycloak-devservices]] | ||||||
=== Dev Services for Keycloak | ||||||
|
||||||
Using link:security-openid-connect-dev-services[Dev Services for Keycloak] is recommended for the integration testing against Keycloak. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
`Dev Services for Keycloak` will launch and initialize a test container: it will create a `quarkus` realm, a `quarkus-app` client (`secret` secret) and add `alice` (`admin` and `user` roles) and `bob` (`user` role) users, where all of these properties can be customized. | ||||||
|
||||||
First prepare `application.properties`. You can start with a completely empty `application.properties` as `Dev Services for Keycloak` will register `quarkus.oidc.auth-server-url` pointing to the running test container as well as `quarkus.oidc.client-id=quarkus-app` and `quarkus.oidc.credentials.secret=secret`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
But if you already have all the required `quarkus-oidc` properties configured then you only need to associate `quarkus.oidc.auth-server-url` with the `prod` profile for `Dev Services for Keycloak`to start a container, for example: | ||||||
|
||||||
[source,properties] | ||||||
---- | ||||||
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus | ||||||
---- | ||||||
|
||||||
If a custom realm file has to be imported into Keycloak before running the tests then you can configure `Dev Services for Keycloak` as follows: | ||||||
|
||||||
[source,properties] | ||||||
---- | ||||||
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus | ||||||
quarkus.keycloak.devservices.realm-path=quarkus-realm.json | ||||||
---- | ||||||
|
||||||
Finally write a test code the same way as it is described in the <<integration-testing-wiremock, Wiremock>> section above. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
The only difference is that `@QuarkusTestResource` is no longer needed: | ||||||
|
||||||
[source, java] | ||||||
---- | ||||||
@QuarkusTest | ||||||
public class CodeFlowAuthorizationTest { | ||||||
} | ||||||
---- | ||||||
|
||||||
[[integration-testing-keycloak]] | ||||||
=== Keycloak | ||||||
=== KeycloakTestResourceLifecycleManager | ||||||
|
||||||
If you work with Keycloak then you can test against a live Keycloak instance by adding the following dependency: | ||||||
If you need to do the integration testing against Keycloak then you are encouraged to do it with <<integration-testing-keycloak-devservices,Dev Services For Keycloak>>. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
Use `KeycloakTestResourceLifecycleManager` for your tests only if there is a good reason not to use `Dev Services for Keycloak`. | ||||||
|
||||||
Start with adding the following dependency: | ||||||
|
||||||
[source,xml] | ||||||
---- | ||||||
|
@@ -798,7 +834,9 @@ If you work with Keycloak then you can test against a live Keycloak instance by | |||||
</dependency> | ||||||
---- | ||||||
|
||||||
and configure `maven.surefire.plugin` as follows: | ||||||
which provides `io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager` - an implementaion of `io.quarkus.test.common.QuarkusTestResourceLifecycleManager` which starts a Keycloak container. | ||||||
|
||||||
And configure `maven.surefire.plugin` as follows: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
[source,xml] | ||||||
---- | ||||||
|
@@ -909,5 +947,5 @@ include::{generated-dir}/config/quarkus-oidc.adoc[opts=optional] | |||||
* https://openid.net/connect/[OpenID Connect] | ||||||
* https://tools.ietf.org/html/rfc7519[JSON Web Token] | ||||||
* link:security-openid-connect-client[Quarkus - Using OpenID Connect and OAuth2 Client and Filters to manage access tokens] | ||||||
* link:security-openid-connect-dev-services[Dev Services for OpenId Connect] | ||||||
* link:security-openid-connect-dev-services[Dev Services for Keycloak] | ||||||
* link:security[Quarkus Security] |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -508,7 +508,7 @@ Note it is also recommended to use `quarkus.oidc.token.audience` property to ver | |||||
Please see link:security-openid-connect-client#token-propagation[Token Propagation] section about the Bearer access token propagation to the downstream services. | ||||||
|
||||||
[[oidc-provider-authentication]] | ||||||
=== Oidc Provider Client Authentication | ||||||
== Oidc Provider Client Authentication | ||||||
|
||||||
`quarkus.oidc.runtime.OidcProviderClient` is used when a remote request to an OpenId Connect Provider has to be done. If the bearer token has to be introspected then `OidcProviderClient` has to authenticate to the OpenId Connect Provider. Please see link:security-openid-connect-web-authentication#oidc-provider-client-authentication[OidcProviderClient Authentication] for more information about all the supported authentication options. | ||||||
|
||||||
|
@@ -602,10 +602,98 @@ public class BearerTokenAuthorizationTest { | |||||
Testing your `quarkus-oidc` `service` application with `OidcWiremockTestResource` provides the best coverage as even the communication channel is tested against the Wiremock HTTP stubs. | ||||||
`OidcWiremockTestResource` will be enhanced going forward to support more complex Bearer token test scenarios. | ||||||
|
||||||
[[integration-testing-keycloak-devservices]] | ||||||
=== Dev Services for Keycloak | ||||||
|
||||||
Using link:security-openid-connect-dev-services[Dev Services for Keycloak] is recommended for the integration testing against Keycloak. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
`Dev Services for Keycloak` will launch and initialize a test container: it will create a `quarkus` realm, a `quarkus-app` client (`secret` secret) and add `alice` (`admin` and `user` roles) and `bob` (`user` role) users, where all of these properties can be customized. | ||||||
|
||||||
First you need to add the following dependency: | ||||||
|
||||||
[source,xml] | ||||||
---- | ||||||
<dependency> | ||||||
<groupId>io.quarkus</groupId> | ||||||
<artifactId>quarkus-test-keycloak-server</artifactId> | ||||||
<scope>test</scope> | ||||||
</dependency> | ||||||
---- | ||||||
|
||||||
which provides a utility class `io.quarkus.test.keycloak.client.KeycloakTestClient` you can use in tests for acquiring the access tokens. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Next prepare your `application.properties`. You can start with a completely empty `application.properties` as `Dev Services for Keycloak` will register `quarkus.oidc.auth-server-url` pointing to the running test container as well as `quarkus.oidc.client-id=quarkus-app` and `quarkus.oidc.credentials.secret=secret`. | ||||||
|
||||||
But if you already have all the required `quarkus-oidc` properties configured then you only need to associate `quarkus.oidc.auth-server-url` with the `prod` profile for `Dev Services for Keycloak`to start a container, for example: | ||||||
|
||||||
[source,properties] | ||||||
---- | ||||||
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus | ||||||
---- | ||||||
|
||||||
If a custom realm file has to be imported into Keycloak before running the tests then you can configure `Dev Services for Keycloak` as follows: | ||||||
|
||||||
[source,properties] | ||||||
---- | ||||||
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus | ||||||
quarkus.keycloak.devservices.realm-path=quarkus-realm.json | ||||||
---- | ||||||
|
||||||
Finally write your test which will be executed in JVM mode: | ||||||
|
||||||
[source,java] | ||||||
---- | ||||||
package org.acme.security.openid.connect; | ||||||
|
||||||
import io.quarkus.test.junit.QuarkusTest; | ||||||
import io.quarkus.test.keycloak.client.KeycloakTestClient; | ||||||
import io.restassured.RestAssured; | ||||||
import org.junit.jupiter.api.Test; | ||||||
|
||||||
@QuarkusTest | ||||||
public class BearerTokenAuthenticationTest { | ||||||
|
||||||
KeycloakTestClient keycloakClient = new KeycloakTestClient(); | ||||||
|
||||||
@Test | ||||||
public void testAdminAccess() { | ||||||
RestAssured.given().auth().oauth2(getAccessToken("alice")) | ||||||
.when().get("/api/admin") | ||||||
.then() | ||||||
.statusCode(200); | ||||||
RestAssured.given().auth().oauth2(getAccessToken("bob")) | ||||||
.when().get("/api/admin") | ||||||
.then() | ||||||
.statusCode(403); | ||||||
} | ||||||
|
||||||
protected String getAccessToken(String userName) { | ||||||
return keycloakClient.getAccessToken(userName); | ||||||
} | ||||||
} | ||||||
---- | ||||||
|
||||||
and in native mode: | ||||||
|
||||||
[source,java] | ||||||
---- | ||||||
package org.acme.security.openid.connect; | ||||||
|
||||||
import io.quarkus.test.junit.QuarkusIntegrationTest; | ||||||
|
||||||
@QuarkusIntegrationTest | ||||||
public class NativeBearerTokenAuthenticationIT extends BearerTokenAuthenticationTest { | ||||||
} | ||||||
---- | ||||||
|
||||||
Please see link:security-openid-connect-dev-services[Dev Services for Keycloak] for more information about the way it is initialized and configured. | ||||||
|
||||||
[[integration-testing-keycloak]] | ||||||
=== Keycloak | ||||||
=== KeycloakTestResourceLifecycleManager | ||||||
|
||||||
If you need to do some integration testing against Keycloak then you are encouraged to do it with <<integration-testing-keycloak-devservices,Dev Services For Keycloak>>. | ||||||
Use `KeycloakTestResourceLifecycleManager` for your tests only if there is a good reason not to use `Dev Services for Keycloak`. | ||||||
|
||||||
If you work with Keycloak then you can test against a live Keycloak instance by adding the following dependency: | ||||||
Start with adding the following dependency: | ||||||
|
||||||
[source,xml] | ||||||
---- | ||||||
|
@@ -616,7 +704,9 @@ If you work with Keycloak then you can test against a live Keycloak instance by | |||||
</dependency> | ||||||
---- | ||||||
|
||||||
and configure `maven.surefire.plugin` as follows: | ||||||
which provides `io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager` - an implementaion of `io.quarkus.test.common.QuarkusTestResourceLifecycleManager` which starts a Keycloak container. | ||||||
|
||||||
And configure the Maven Surefire plugin as follows: | ||||||
|
||||||
[source,xml] | ||||||
---- | ||||||
|
@@ -917,5 +1007,5 @@ Note Quarkus `web-app` applications always require `quarkus.oidc.client-id` prop | |||||
* https://openid.net/connect/[OpenID Connect] | ||||||
* https://tools.ietf.org/html/rfc7519[JSON Web Token] | ||||||
* link:security-openid-connect-client[Quarkus - Using OpenID Connect and OAuth2 Client and Filters to manage access tokens] | ||||||
* link:security-openid-connect-dev-services[Dev Services for OpenId Connect] | ||||||
* link:security-openid-connect-dev-services[Dev Services for Keycloak] | ||||||
* link:security[Quarkus Security] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,6 @@ | ||
#quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus | ||
quarkus.oidc.client-id=quarkus-web-app | ||
quarkus.oidc.credentials.secret=secret | ||
quarkus.oidc.application-type=web-app | ||
|
||
quarkus.keycloak.devservices.enabled=false | ||
#quarkus.oidc.application-type=web-app | ||
|
||
quarkus.log.category."com.gargoylesoftware.htmlunit.javascript.host.css.CSSStyleSheet".level=FATAL | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.