Keycloak Testcontainers
In this bonus lab we'll see how we can leverage Testcontainers and Keycloak Testcontainer to create a client-side end2end test for our OAuth 2.0 and OpenID Connect 1.0 compliant Resource Server.
Lab Contents
Learning Targets
In this lab we will add end-to-end tests for our OAuth2/OIDC compliant resource server.
We will use Keycloak Testcontainer as identity provider for this. So the tests will run using Keycloak as real identity provider.
In this bonus lab you will learn how to:
How to write automated client-side end2end tests using RestAssured
How to get a real JWT from Keycloak in the tests using Testcontainers and Keycloak Testcontainer.
Folder Contents
You find 2 applications in the folder bonus-labs/keycloak-test-containers:
library-server-initial: This is the application we will use as starting point for this lab
library-server-complete: This application is the completed reference for this lab
Start the Lab
In this lab we will implement:
A unit test to verify the LibraryUserJwtAuthenticationConverter.
An integration test to verify correct authentication & authorization for the books API using JWT
Please start this lab with the project located in bonus-labs/keycloak-test-containers/library-server-initial.
Step 1: Add required dependencies
First we need to add the required dependencies
build.gradle
Step 2: Extend the End2end Integration Test with Testcontainers
Now let's start with building the test. Open the existing test class com.example.library.server.api.BookApiEnd2EndTest and add the missing parts.
In the test class you already will find two test cases for the well-known books api:
verifyGetBooks(): This tests the happy path accessing the list of books with a valid JWT retrieved from Keycloak
verifyGetBooksFail(): This tests the error path getting http status 401 (unauthenticated) when trying the same without a token
First we'll add all the required parts for Testcontainers and Keycloak Testcontainer.
The annotation
@Testcontainersscans and configures all testcontainers marked with the other annotation@Container.Then we create an instance of
KeycloakContainerthat loads the same realm configuration from keycloak_realm_workshop.json as used in the real Keycloak instance.In the
setup()operation we retrieve the required token endpoint url by retrieving the base url viakeycloak.getAuthServerUrl()
With this code in place you should already be able to run the tests. You will notice that running the tests will last some time due to starting the Keycloak docker container first. After the container started successfully the test cases will run. Here you will recognize that the test for the happy path is still failing. This is caused by the wrong JWT issuer claim. The Keycloak testcontainer runs at a different port than the Keycloak from previous labs. The issuer claim has changed as well.
No worries, we will change this in the next section.
Step 3: Reconfigure the Issuer Claim for JWT
Open again the same test class and change the setup() operation as shown here:
To change the issuer and jwks uri, we dynamically override the oauth2 resource server configuration using DynamicPropertyRegistry instance, and the @DynamicPropertySource spring test support.
Now we can just set the issuer to the configured value of the Keycloak testcontainer.
Now the testing class should be complete and look like the following one:
Step 4: Running the Tests
Now you can run the tests and all tests should run fine and report a green status. Please also notice that the test is tagged with @Tag("end2end"). This way you can for example exclude such long-running tests from the regular build and instead only run these as part of a nightly build.
Actually the gradle build excludes this test here as well using the following additional snippet in the build.gradle file:
This ends this bonus lab. If you like the approach with the Testcontainers then you may look for other supported testcontainers like for example databases (this is also a great possibility to test against the real database instead of simulating this using a H2 in-memory database).
Last updated
Was this helpful?