1. Overview
Keycloak is a free and open-source identity and access management program, often used in our software stacks today. During the testing phase, it may be useful to disable its use to focus on business testing. We may also not have a Keycloak server in our test environment.
In this tutorial, we’ll disable the configuration put in place by the Keycloak starter. We’ll also look at modifying Spring Security when it’s enabled in our project.
2. Disabling Keycloak in a Non-Spring-Security Environment
We’ll start by looking at how to disable Keycloak in an application that doesn’t use Spring Security.
2.1. Application Setup
Let’s start by adding the spring-boot-starter-oauth2-client dependency to our project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Additionally, we need to add the spring-boot-starter-oauth2-resource-server dependency. It will allow us to validate a JWT token with the Keycloak server. Hence, let’s add it to our pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
Next, we’ll add to our application.properties the configuration for our Keycloak server:
spring.security.oauth2.client.registration.keycloak.client-id=login-app
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.provider.keycloak.issuer-uri=
http://localhost:8080/realms/SpringBootKeycloak
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
Finally, let’s add a UserController that retrieves a User:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{userId}")
public User getCustomer(@PathVariable Long userId) {
return new User(userId, "John", "Doe");
}
}
2.2. Disabling Keycloak
Now that our application is in place, let’s write a simple test to get a user:
@Test
public void givenUnauthenticated_whenGettingUser_shouldReturnUser() {
ResponseEntity<User> responseEntity = restTemplate.getForEntity("/users/1", User.class);
assertEquals(HttpStatus.SC_OK, responseEntity.getStatusCodeValue());
assertNotNull(responseEntity.getBody()
.getFirstname());
}
This test will fail because we didn’t provide any authentication to restTemplate, or because the Keycloak server is not available.
The Keycloak adapter implements the Spring autoconfiguration of Keycloak security. Autoconfigurations rely on the presence of a class in the classpath or on the value of a property. Specifically, the @ConditionalOnProperty annotation is very handy for this particular need.
To disable Keycloak security, we need to inform the adapter that it should not load the corresponding configuration. We can do this by assigning the property as follows:
keycloak.enabled=false
If we launch our test again, it will now succeed without any authentication involved.
3. Disabling Keycloak in a Spring Security Environment
We often use Keycloak in combination with Spring Security. In this case, it’s not enough to disable the Keycloak configuration, but we also need to modify the Spring Security configuration to allow anonymous requests to reach the controllers.
3.1. Application Setup
Let’s start by adding the spring-boot-starter-security dependency to our project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Next, we create a SecurityFilterChain bean to define the configuration needed for Spring Security :
@Configuration
@EnableWebSecurity
public class KeycloakSecurityConfig {
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeHttpRequests(auth -> auth.anyRequest()
.authenticated());
http.oauth2Login();
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
}
Here, we’re configuring Spring Security to allow requests from authenticated users only.
3.2. Disabling Keycloak
As well as disabling Keycloak like we did earlier, we now also need to disable Spring Security.
We could use profiles to tell Spring whether or not to activate the Keycloak configuration during our tests:
@Configuration
@EnableWebSecurity
@Profile("tests")
public class KeycloakSecurityConfig {
// ...
}
However, a more elegant way is to reuse the keycloak.enable property, similar to the Keycloak adapter:
@Configuration
@EnableWebSecurity
@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true", matchIfMissing = true)
public class KeycloakSecurityConfig {
// ...
}
As a result, Spring only enables Keycloak configuration if the keycloak.enable property is true. In case the property is missing, matchIfMissing enables it by default.
As we’re using the Spring Security starter, it’s not enough to disable our Spring Security configuration. Indeed, following Spring’s opinionated defaults configuration principles, the starter will create a default security layer.
Let’s create a configuration class to disable it:
@Configuration
@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "false")
public class DisableSecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.permitAll();
return http.build();
}
}
We’re still using our keycloak.enable property, but this time Spring enables the configuration if its value is set to false.
4. Conclusion
In this article, we looked at how to disable Keycloak security in a Spring environment, with or without Spring Security.
As usual, all the code samples used in this article can be found over on GitHub.