springspring-bootspring-securityh2

Spring Security version 6 issues with SecurityFilterChain


I am trying to make a small project with the recent versions of Spring Boot (3.0.6) and Spring Security version 6. The problem is that Spring has deprecated a lot of code regarding establishing auth system.

We used to work with WebSecurityConfigurerAdapter and everything worked fine, now we have to use SecurityFilterChain instead. I found many examples on the internet where people use SecurityFilterChain differently; some use antMatchers (deprecated), some mvcMatchers (deprecated) and some use requestMatchers, which is supported in the last version. Even the official documentations doesn't help at all in this regard. For example, when I use the following code, the h2-console become inaccessible:

package com.example.myproj.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests()
                .requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll()
                .and() 
            .authorizeHttpRequests()
                .requestMatchers("/users/**")
                .permitAll()
                .and()
            .httpBasic();
        return http.build();
    }
}

Here is the h2-console configuration in the application.properties:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Here is the pom.xml for reference:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>myproj</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>myproj</name>
    <description>Demo project for Spring Boot and Spring Security</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

So what to do? Some emphasis the use of Lamda DSL for the new version of Spring Security. I need a firm guideline because it's chaos now with Spring Security.


Solution

  • You have to enable H2 console, see 9.1.5. Using H2’s Web Console

    9.1.5. Using H2’s Web Console

    The H2 database provides a browser-based console that Spring Boot can auto-configure for you. The console is auto-configured when the following conditions are met:

    • You are developing a servlet-based web application.
    • com.h2database:h2 is on the classpath.
    • You are using Spring Boot’s developer tools.

    If you are not using Spring Boot’s developer tools but would still like to make use of H2’s console, you can configure the spring.h2.console.enabled property with a value of true.

    You have to disable CSRF and set X-Frame-Options, see Accessing the H2 Console in a Secured Application:

    Accessing the H2 Console in a Secured Application

    H2 Console uses frames and, as it is intended for development only, does not implement CSRF protection measures. If your application uses Spring Security, you need to configure it to

    • disable CSRF protection for requests against the console,
    • set the header X-Frame-Options to SAMEORIGIN on responses from the console.

    More information on CSRF and the header X-Frame-Options can be found in the Spring Security Reference Guide.

    In simple setups, a SecurityFilterChain like the following can be used:

    @Profile("dev")
    @Configuration(proxyBeanMethods = false)
    public class DevProfileSecurityConfiguration {
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        SecurityFilterChain h2ConsoleSecurityFilterChain(HttpSecurity http) throws Exception {
            http.securityMatcher(PathRequest.toH2Console());
            http.authorizeHttpRequests(yourCustomAuthorization());
            http.csrf((csrf) -> csrf.disable());
            http.headers((headers) -> headers.frameOptions().sameOrigin());
            return http.build();
        }
    }