Introduction

Integration testing is an essential part of modern application development, ensuring that different parts of an application work together as expected. In this article, we will explore how to perform integration testing using Keycloak for identity and access management, Spring Security for securing applications, Spring Boot for rapid application development, and Spock Framework for testing. We will delve into setting up the environment, configuring the components, and writing integration tests to verify the seamless interaction between these components.

Setting Up the Environment

Prerequisites

Before we begin, ensure you have the following installed on your system:

  • Java Development Kit (JDK) 11 or higher
  • Maven or Gradle
  • Docker (for running Keycloak)
  • IDE of your choice (IntelliJ IDEA, Eclipse, etc.)

Keycloak Setup

Keycloak is an open-source identity and access management solution. To set up Keycloak:

  1. Pull the Keycloak Docker image:

    bash

    docker pull jboss/keycloak
  2. Run the Keycloak container:

    bash

    docker run -d --name keycloak -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak
  3. Access the Keycloak admin console at http://localhost:8080/auth and log in with the credentials admin/admin.
  4. Create a realm, client, and users as needed for your application.

Spring Boot Project Setup

Create a Spring Boot project using Spring Initializr (https://start.spring.io/) with the following dependencies:

  • Spring Web
  • Spring Security
  • Spring Boot Actuator
  • Spring Data JPA
  • H2 Database
  • Keycloak Spring Boot Adapter

Application Configuration

Configure Keycloak in your Spring Boot application by adding the following properties to application.yml:

yaml

keycloak:
realm: your-realm
resource: your-client-id
auth-server-url: http://localhost:8080/auth
ssl-required: external
public-client: true
credentials:
secret: your-client-secret
bearer-only: true
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password: password
jpa:
hibernate:
ddl-auto: update
show-sql: true

Spring Security Configuration

Create a configuration class to integrate Spring Security with Keycloak:

java

import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers(“/public/**”).permitAll()
.anyRequest().authenticated();
}@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
}

Writing Integration Tests

Test Dependencies

Add the following dependencies to your pom.xml or build.gradle for Spock Framework and integration testing:

xml

<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>2.0-groovy-3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>2.0-groovy-3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>15.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

Spock Test Configuration

Create a base test configuration for Spock:

groovy

import org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory
import org.keycloak.adapters.springsecurity.client.KeycloakRestTemplate
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import spock.lang.Specification
@SpringBootTest
class BaseIntegrationTest extends Specification {@Configuration
static class TestConfig {@Bean
KeycloakClientRequestFactory keycloakClientRequestFactory() {
new KeycloakClientRequestFactory()
}@Bean
KeycloakRestTemplate keycloakRestTemplate(KeycloakClientRequestFactory keycloakClientRequestFactory) {
new KeycloakRestTemplate(keycloakClientRequestFactory)
}
}
}

Writing Integration Tests

Create an integration test for a secured endpoint:

groovy

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import spock.lang.Shared
import spock.lang.Stepwise
@Stepwise
class SecuredEndpointIntegrationTest extends BaseIntegrationTest {@Autowired
TestRestTemplate restTemplate@Shared
String accessTokendef setupSpec() {
// Obtain access token from Keycloak
accessToken = getAccessToken(‘username’, ‘password’)
}def “should return 401 when accessing secured endpoint without token”() {
when:
ResponseEntity<String> response = restTemplate.getForEntity(‘/secured’, String)then:
response.statusCode == HttpStatus.UNAUTHORIZED
}def “should return 200 when accessing secured endpoint with token”() {
given:
HttpHeaders headers = new HttpHeaders()
headers.setBearerAuth(accessToken)
HttpEntity<String> entity = new HttpEntity<>(headers)

when:
ResponseEntity<String> response = restTemplate.exchange(‘/secured’, HttpMethod.GET, entity, String)

then:
response.statusCode == HttpStatus.OK
}

private String getAccessToken(String username, String password) {
// Implement the logic to obtain an access token from Keycloak
// This could involve making a POST request to Keycloak’s token endpoint
}
}

Conclusion

In this article, we’ve walked through the process of setting up integration testing for a Spring Boot application secured with Keycloak using the Spock Framework. We began by setting up the necessary environment, including Keycloak, Spring Boot, and the associated dependencies. We configured Spring Security to integrate with Keycloak, providing robust security for our application.

The Spock Framework proved to be an excellent choice for writing expressive and powerful tests, allowing us to verify that our secured endpoints were behaving as expected. We covered the essentials of creating a test configuration, obtaining access tokens, and performing integration tests against secured endpoints.

By following these steps, developers can ensure that their Spring Boot applications are not only functional but also secure, with integration tests providing confidence that the components work together seamlessly. This approach to integration testing helps catch issues early in the development process, leading to more robust and reliable applications.

Integration testing with Keycloak, Spring Security, Spring Boot, and Spock Framework provides a comprehensive solution for modern application security and testing needs. With the right setup and configuration, developers can leverage these powerful tools to build and test secure, scalable, and maintainable applications.