Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

H2-Database console not opening with Spring-Security

I'm using the H2-Database and Spring Security, but I'm unable to open it in the browser at http://localhost:8080/h2-console

Here my pom.xml (only the H2 entry)

<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <scope>runtime</scope>
</dependency>

Here my application.properties

spring.datasource.url=jdbc:h2:file:/data/noNameDB
spring.h2.console.enabled=true
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=admin
spring.datasource.password=admin
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.path=/h2-console
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jackson.serialization.fail-on-empty-beans=false

And here is my SecurityConfig.java

import com.example.noName.security.JwtAuthenticationEntryPoint;
import com.example.noName.security.JwtAuthenticationFilter;
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.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;



@Configuration
@EnableWebSecurity
public class SecurityConfig {


    private static final String[] AUTH_WHITE_LIST = {
            "/v3/api-docs/**",
            "/swagger-ui/**",
            "/v2/api-docs/**",
            "/swagger-resources/**",
            "/h2-console/**",
            "/console/**",
            "/account/**"
    };

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public AuthenticationManager authenticationManager(
            AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }



    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeHttpRequests()
                .requestMatchers(AUTH_WHITE_LIST)
                .permitAll()
                .and()
                .headers()
                .frameOptions()
                .disable()
                .and()
                .authorizeHttpRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .and()
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .httpBasic();

        return http.build();
    }

}

The following is shown in the console if I try to access the console via http://localhost:8080/h2-console

INFO 3664 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO 3664 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
INFO 3664 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms

I have already tried everything I could find on the Internet.

The funny thing is that the "exception handling" works for Swagger. If I try to access the database via:

http://localhost:8080/h2-console

I always get the error:

401 - Unauthorized

Each one is strange, because the access was allowed in the SecurityConfig.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .cors()
            .and()
            .csrf()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(jwtAuthenticationEntryPoint)
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeHttpRequests()
            .requestMatchers(AUTH_WHITE_LIST)
            .permitAll()
            .and()
            .headers()
            .frameOptions()
            .disable()
            .and()
            .authorizeHttpRequests()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic()
            .and()
            .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .httpBasic();

    return http.build();
}

I can access the database through an internal database test. This is provided by Intellij.

However working/editing in the database is not possible through this.

AND:

If I change the AUTH_WHITE_LIST to this, it works.

private static final String[] AUTH_WHITE_LIST = {
       "/**"
};
like image 413
Marc Avatar asked Apr 12 '26 09:04

Marc


2 Answers

I could reproduce with spring-boot:3.0.0(web, security, h2, ...) and:

return http
        .authorizeHttpRequests()
        .requestMatchers("/h2-console/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .and()
        .csrf().ignoringRequestMatchers("/h2-console/**")
        .and()
        .headers().frameOptions().sameOrigin()
        .and()
        .build();

(/h2-console is still protected!)

Fix:

(spring-boot-way):

import static //
org.springframework.boot.autoconfigure.security.servlet.PathRequest.toH2Console; // !
...
  .requestMatchers(toH2Console()).permitAll()
  ...
  .csrf().ignoringRequestMatchers(toH2Console())

Refs:

  • https://jessitron.com/2020/06/15/spring-security-for-h2-console/
  • PathRequest

It uses internally:

new AntPathRequestMatcher(h2ConsoleProperties.get().getPath() + "/**");

which seems to be different/better than the requestMatcher(String... paths) (AbstractRequestMatcherRegistry), which invokes this (with method==null):

public C requestMatchers(HttpMethod method, String... patterns) {
   List<RequestMatcher> matchers = new ArrayList<>();
   if (mvcPresent) {
      matchers.addAll(createMvcMatchers(method, patterns)); // <- we land here obviously
   } else {
      matchers.addAll(RequestMatchers.antMatchers(method, patterns));     
   }
  return requestMatchers(matchers.toArray(new RequestMatcher[0]));
}

... alternatives:

  • RequestMatchers.antMatcher(null, pathToH2+"/**").
  • AntPathRequestMatcher (for ignore case (and all http methods), prefer constructors to factories;)
  • MvcMatcher (is not possible for h2-console, since it is not mvc;(

BUT/AND

I would not do it (unsecured) in production!

like image 149
xerx593 Avatar answered Apr 14 '26 23:04

xerx593


In Spring boot 3, you need to add the following configurations:

first

.csrf(csrf -> csrf
            .ignoringRequestMatchers(toH2Console())
            .disable())

second

.authorizeHttpRequests(auth -> auth
        .requestMatchers(toH2Console()).permitAll())

third

.headers(headers -> headers.frameOptions(FrameOptionsConfig::disable))
like image 34
Artem Zubkov Avatar answered Apr 14 '26 21:04

Artem Zubkov