In a Spring Boot project we enabled Spring Security and applied Keycloak authentication with bearer token like described in the following articles:
https://www.keycloak.org/docs/3.2/securing_apps/topics/oidc/java/spring-security-adapter.html
https://www.keycloak.org/docs/3.2/securing_apps/topics/oidc/java/spring-boot-adapter.html
But i can't find any recommendations how to make automation tests so that the Keycloak config is applied.
So, how to test/mock/verify the Keycloak configuration when Spring security is enabled? One really annoying thing: by default Spring activates csrf security filter, but how to avoid testing it?
(Note: we use bearer tokens, so looks like @WithMockUser
is not applicable in this case)
A bonus question:
basically we don't want to verify security on each controller integration test, so is it possible to verify security separately from the controllers integration tests (those which use @SpringBootTest
, @WebAppConfiguration
, @AutoConfigureMockMvc
and so on?
I work on the activiti project and we've been using keycloak with spring boot and hit the same questions. There is a keycloak test helper class called KeycloakSecurityContextClientRequestInterceptor that we've customized a little bit. That references the realm and user to use for testing. The we set those properties in tests that use keycloak. That can also be used to switch users during a set of tests.
For tests where we don't want to use keycloak we've so far followed a practice of keeping those at a different level in our project and therefore in a different submodule. This lets us keep the keycloak maven dependencies out of that layer so that keycloak simply isn't enabled on them.
One solution is using WireMock for stubbing the keycloak authorisation server. Therefore you can use the library
spring-cloud-contract-wiremock
(see https://cloud.spring.io/spring-cloud-contract/1.1.x/multi/multi__spring_cloud_contract_wiremock.html), which offers an easy spring boot integration. You can simply add the dependency as described. Furthermore i use jose4j for creating mocked access tokens the same way as Keycloak does as JWTs. All you have to do is stubbing the endpoints for Keycloak OpenId Configuration and the JSON Web Key Storage, since the Keycloak Adapter does only request those for validation of access tokens in the Authorization Header.A minimal working standalone example, that needs to be customized at one place though (see Important Notes), with a few explanations is listed in the following:
KeycloakTest.java:
wiremock.properties:
Test Setup
The annotation
@AutoConfigureWireMock(port = 0)
will start a WireMock server at a random port, which is set to the propertywiremock.server.port
automatically, so it can be used to override thekeycloak.auth-server-url
property for the Spring Boot Keycloak Adapter accordingly (see wiremock.properties)For generating the JWT, that is used as a Access Token, i do create a RSA key pair with jose4j, that is declared as a test class attribute, since i do need to initialize it during test setup alongside the WireMock Server.
It is then initialized during test setup as following:
The choice for the keyId does not matter. You can choose whatever you want, as long as it is set. The chosen algorithm and the use do matter though and must be adapted exactly as in the example.
With this the JSON Web Key Storage endpoint of the Keycloak Stub can be set accordingly as follows:
Except this another endpoint needs to be stubbed for keycloak as mentioned earlier. If not cached, the keycloak adapter needs to request the openid configuration. For a minimal working example all endpoints need to be defined in the config, that is returned from the OpenId Configuration Endpoint:
Token Generation
Generation of the token is implemented in
generateJWT()
with heavy use of jose4j . The most important point to note here is, that the private key of the same generated JWK as the one initialized during the test setup for wiremock has to be used.Except this the the code is adapted mainly from the example at https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples.
One can now adjust or extend the claims as seen fit for one's own specific test setup. The minimal example in the posted snippet represents a typical example for a JWT produced by Keycloak.
Test Execution
The generated JWT can be used as usual in the Authorization Header to send a request to a REST endpoint:
For representing a standalone example the test class does have a simple Restcontroller defined as an inner class, that is used for the test.
Important Notes
I did introduce a custom
TestController
for testing purposes, so it had been neccessary to define a custom ContextConfiguration to load it in aWebMvcTest
as follows:Apart from the TestController itself a bunch of Configuration Beans regarding Spring Security and the Keycloak Adapter are included like
SecurityConfig.class
andCustomKeycloakSpringBootConfigResolver.class
to have it work. These need to be replaced by your own Configuration of course. For the sake of completeness those classes will be listed too in the following:SecurityConfig.java:
CustomKeycloakSpringBootConfigResolver.java:
Partial answer applying to the "bonus" question only (
@Component
unit-tests): I just wrote a set of libs to ease unit-testing of secured Spring apps. I only run such tests and e2e tests (including rich client front-end and actual authorization-server).It includes a
@WithMockKeycloackAuth
annotation, along with Keycloak dedicatedMockMvc
request post-processorSample usage:
Different libs are available from maven-central, choose one of following according to your use-case: