Course – LSS – NPI (cat=Security/Spring Security)
announcement - icon

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security:

>> CHECK OUT THE COURSE

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(name = "userId") 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(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(auth -> auth.anyRequest()
                .permitAll())
            .oauth2Login(Customizer.withDefaults())
            .oauth2ResourceServer(httpSecurityOAuth2ResourceServerConfigurer -> 
                httpSecurityOAuth2ResourceServerConfigurer.jwt(Customizer.withDefaults()));
        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(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(request -> request.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.

Course – LSS (cat=Security/Spring Security)

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security:

>> CHECK OUT THE COURSE
res – Security (video) (cat=Security/Spring Security)
Comments are closed on this article!