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:
- Pull the Keycloak Docker image:
bash
docker pull jboss/keycloak
- Run the Keycloak container:
bash
docker run -d --name keycloak -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak
- Access the Keycloak admin console at
http://localhost:8080/auth
and log in with the credentialsadmin/admin
. - 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;
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers(“/public/**”).permitAll()
.anyRequest().authenticated();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
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
@SpringBootTestclass BaseIntegrationTest extends Specification {
@Configurationstatic class TestConfig {
@BeanKeycloakClientRequestFactory keycloakClientRequestFactory() {
new KeycloakClientRequestFactory()
}
@BeanKeycloakRestTemplate 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
@Stepwiseclass SecuredEndpointIntegrationTest extends BaseIntegrationTest {
@AutowiredTestRestTemplate restTemplate
@SharedString accessToken
def 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.