Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can greatly simplify our codebase. However, it adds another external dependency that will complicate the integration testing. As a remedy, we can switch to native Spring Security when executing tests to verify only the business rules for access control instead of cluttering the code with Keycloak dependencies.
- A Spring Boot project with security configuration for Keycloak described in the Keycloak with Spring Boot #1 – Configure Spring Security with Keycloak post.
- Dependencies that provide support for Spring Security and testing. Below are the relevant dependencies from my project:
- I’m working on a Spring Boot REST API that you can find in my
keycloak-spring-bootrepository. If you want to run the app locally, visit the project repository on GitHub and follow the directions in the README.md file.
Why we need to overwrite configuration in tests
For example, after we add Keycloak config to a project, Spring MVC tests will fail to load the
ApplicationContext due to the following error:
Currently, there is no default way to disable Keycloak protection (note that the property keycloak.enabled=false is not supported).
While we could provide just enough Keycloak configuration to run the tests, it would introduce irrelevant details into the code. Therefore, we need to ensure a security config that keeps the test code clean and still allows API access rules to be verified.
Configure integration tests to use Spring Security instead of Keycloak
First, we’ll make the Keycloak setup dependent on a custom application property. Then we’ll configure our tests to use just Spring Security.
Make the Keycloak config load dependent on a custom property
We’re going to create a custom application property to control the loading of the security config. An important point to remember is that I want Keycloak to be used by default. In other words, I only want to turn it off in testing.
application.properties file in the
test/resources directory and copy the following property:
When executing tests, Spring Boot will only see the properties defined in this file. If you have any properties that should also be used in your tests, be sure to copy them to this file as well. The advantage of this approach is that it removes all irrelevant properties from the testing context and also provides a clear view of our testing setup.
Next, we need to configure our app to use Keycloak either when our custom property explicitly says so or when it hasn’t been specified at all (by default). Therefore, we’re going to aply the ConditionalOnProperty annotation to all Keycloak-related configuration classes (there are two in my project):
Thanks to specifying the
matchIfMissing attribute, the Keycloak configuration is our default security configuration. However, it won’t be used when running tests because we explicitly disabled it in the
Define common security rules
As you may have noticed, we don’t have any security setup for our testing at the moment. Ideally, we want to test the business rules for API security without duplicating it in the tests. Therefore, I’m going to extract the common configuration into a static method so that I can reuse it in my tests:
As a result, I can reuse the
SecurityConfig::configureApiSecurity method outside of the Keycloak configuration class.
Apply security configuration in tests
Consequently, we can now provide a separate security configuration for the tests. Create a class in the
test package that:
- uses the @Configuration annotation,
- is enabled when the
security.conifg.use-keycloakproperty is set to
- uses the
SecurityConfig::configureApiSecuritymethod we defined earlier.
You can see my conifg class below:
This is all I need to apply my security config in tests without coupling it with an external authorization server.
Finally, by running tests from my
ProductControllerTest class, I can verify the actual configuration in logs:
As we can see, a user password is generated automatically according to the default Spring Security specification and there is no mention of any Keycloak configuration.
More on using Spring Security instead of Keycloak in tests
- Response to How to disable Keycloak question on StackOverflow
- Document how to use this if Keycloak is on the classpath