Reputation: 1126
We recently upgraded from Spring Boot 1.4.1 to 1.5.2. One of the features of 1.5.2 is that if Spring Security is part of the package then it is protected by basic auth. I am unable to access the /h2-console
even after basic auth. It throws 403 forbidden.
application.yml
:
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:file:../app-db/app_db;AUTO_SERVER=TRUE
username: sa
password: sa
initialize: false
jpa:
hibernate:
ddl-auto: validate
show-sql: true
database-platform: org.hibernate.dialect.H2Dialect
h2:
console:
enabled: true
settings:
web-allow-others: true
allowed:
resources: /h2-console/**
I have even explicitly allowed /h2-console/**
httpSecurity.authorizeRequests()
.antMatchers(allowedResources)
.permitAll()
I keep getting 403 when trying to access localhost:8080/h2-console
.
I tried many settings as well as putting:
management.security.enabled=true
security.basic.enabled=true
But I am unable to access the h2-console.
Upvotes: 50
Views: 68699
Reputation: 1403
As of 2024 July, with up-to-date S/W versions, this Bean solved the h2-console access 403 error:
@Bean
WebSecurityCustomizer ignoringCustomizer() {
return (web) -> web.ignoring().requestMatchers("/h2-console/**");
}
Refer https://www.baeldung.com/spring-security-httpsecurity-vs-websecurity#1-the-ignoring-method
For your reference, included is a screen-shot containing the above bean -
Upvotes: 1
Reputation: 5535
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests
.requestMatchers("/test/**").authenticated()
.requestMatchers("/h2-console/**").permitAll());
http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.csrf(AbstractHttpConfigurer::disable);
http.headers(h -> h.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable));
return (SecurityFilterChain) http.build();
}
Upvotes: 1
Reputation: 1
the only reason mine wasn't working because i had not used the @Bean annotation and hence the springsecurity didn't new about my method
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth->auth.anyRequest().permitAll());
//in case of direct page visit show the login page
http.formLogin(withDefaults());
http.csrf(csrf->csrf.disable());
http.headers(headers->headers.frameOptions(frameoptions->frameoptions.disable()));
return http.build();
}
Upvotes: 0
Reputation: 108
Here is an updated config example for spring security 6
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
MvcRequestMatcher.Builder matcher(HandlerMappingIntrospector handlerMappingIntrospector) {
return new MvcRequestMatcher.Builder(handlerMappingIntrospector);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, MvcRequestMatcher.Builder mvcMatcher) throws Exception {
http.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(mvcMatcher.pattern("/endpoint1")).permitAll() // just an example of an endpoint
.requestMatchers(mvcMatcher.servletPath("/h2-console").pattern("**")).permitAll()
.anyRequest().authenticated()
)
.csrf(AbstractHttpConfigurer::disable)
.headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable));
return http.build();
}
}
Upvotes: 2
Reputation: 332
With Spring Boot 3, the following works for me:
@Configuration
class securityConfig {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(new AntPathRequestMatcher("/h2-console/**"));
}
}
Upvotes: 14
Reputation: 3163
With SpringBoot version 3.0.3 and Java 17, the below code works for me:
@Configuration
public class SecurityConfiguration {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().anyRequest();
}
}
Application.properties file contains below configuration:
spring.application.name=order-service
server.port=8080
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:dbapp
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.security.user.name=user
spring.security.user.password=password
Upvotes: 5
Reputation: 109
Spring Boot's PathRequest
class has a method toH2Console()
that returns RequestMatcher
. It reads H2 console path from H2ConsoleProperties
, so if you have modified spring.h2.console.path
property, you'll get a corresponding matcher
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf().ignoringRequestMatchers(PathRequest.toH2Console()).and()
.headers().frameOptions().sameOrigin().and()
// ...
You could use same matcher in http.authorizeHttpRequests(...)
Also if you wonder why .csrf().ignoringRequestMatchers("h2-console/**")
doesn't work, that's because MvcRequestMatcher
treats requests as contextPath + pathWithinApplication and tries to match pattern with the latter, e.g. /h2-console/login.do
has contextPath = h2-console
and pathWithinApplication = login.do
, and "h2-console/**"
pattern doesn't match login.do
.
So you would have to write something like this
public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector handlerMappingIntrospector) throws Exception {
MvcRequestMatcher mvcRequestMatcher = new MvcRequestMatcher.Builder(handlerMappingIntrospector)
.servletPath("/h2-console")
.pattern("/**");
return http
.csrf().ignoringRequestMatchers(mvcRequestMatcher).and()
.headers().frameOptions().sameOrigin().and()
// ...
(but still I would recommend using .toH2Console()
option)
Upvotes: 0
Reputation: 73
As WebSecurityConfigurerAdapter
is deprecated from Spring Security 5.7.0-M2, a new way to do this is to use permitAll
via HttpSecurity#authorizeHttpRequests
as recommended in this Spring blog.
You also need to disable CSRF but only for H2-console. And then allow X-Frame options for frames from the same origin of the page.
It is still not recommended to use this in production but with this, you can continue to test your security with CSRF enable for the rest of the site while still having access to H2-console.
Updated for Spring Security 6.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests()
.requestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/**")).permitAll()
.and()
.csrf().ignoringRequestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/**"))
.and()
.headers(headers -> headers.frameOptions().sameOrigin())
.build();
}
Upvotes: 5
Reputation: 104
Please note these settings are not recommended for Production:
To enable access to the h2 console, which spring security disallows, do this:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests()
.antMatchers("/", "/**", "/console/**").permitAll()
.and()
.csrf().disable()
.headers().frameOptions().disable()
.build();
}
Upvotes: 1
Reputation: 1451
Though the top voted answer is correct.
As of now WebSecurityConfigurerAdapter is deprecated in newer spring security version and the way to go about it is creating Bean for WebSecurityCustomizer
. Below Bean in your security configuration class can do the trick.
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/h2-console/**");
}
Upvotes: 7
Reputation: 1106
With respect to WebSecurityConfigurerAdapter
I think more appropriate and well explained answer is available here
Although I have added sample code and it's works fine for me, not only for h2-console but also for Swagger-UI.
private static final String[] AUTH_WHITELIST = {
// -- Swagger UI v2
"/v2/api-docs",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**",
// -- Swagger UI v3 (OpenAPI)
"/v3/api-docs/**",
"/swagger-ui/**",
// other public endpoints
"/h2-console/**",
};
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/hello").hasAuthority("USER")
.and().authorizeRequests().antMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated()
.and().headers().frameOptions().sameOrigin()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
Upvotes: 2
Reputation: 1837
I also encountered the same problem when I'm using spring security. Please note the below configuration in the application.properties
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.datasource.url=jdbc:h2:file:~/test
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
In the security configuration under the configure method I've included the following and I'm able to access the h2 console.
.antMatchers( "/h2/**").permitAll()
Upvotes: 2
Reputation: 1253
Spring security blocks /h2-console (or the path you configured in your application.yaml) path for H2 database.
To access the H2 console just add the below code to your WebSecurityConfigurerAdapter.
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/h2-console/**").permitAll();
http.csrf().disable();
http.headers().frameOptions().disable();
}
}
Don't use this configuration in a production environment. =)
Upvotes: 91
Reputation: 1229
Since H2 has it's own authentication provider, you can skip the Spring Security for the path of h2 console entirely in the same way that you do for your static content.
In order to do that, in your Spring security config, you have to override the configuration method which takes an instance of org.springframework.security.config.annotation.web.builders.WebSecurity
as a parameter instead of the one which takes an instance of org.springframework.security.config.annotation.web.builders.HttpSecurity
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/h2-console/**");
}
If you're using h2 in a production environment, make sure you set up the proper security measures (things like, setting a non-obvious path, good password, ip white list) for your h2 console.
Upvotes: 100
Reputation: 2696
@Configuration
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", matchIfMissing = true)
static class H2ConsoleSecurityConfiguration
As you can see the source code in spring boot, if you enable the basic, the spring boot will load spring security configuration H2ConsoleSecurityConfigurer
with order SecurityProperties.BASIC_AUTH_ORDER - 10
, and the authentication is base on your configuration in security. This is the default security configuration:
public void configure(HttpSecurity http) throws Exception {
String path = this.console.getPath();
String antPattern = path.endsWith("/")?path + "**":path + "/**";
HttpSecurity h2Console = http.antMatcher(antPattern);
h2Console.csrf().disable();
h2Console.httpBasic();
h2Console.headers().frameOptions().sameOrigin();
// the default role is `USER` and `management.security.roles`
String[] roles = (String[])this.security.getUser().getRole().toArray(new String[0]);
// this value is base `security.basic.authorize-mode`, `role`, 'authenticated' and `none`
SecurityAuthorizeMode mode = this.security.getBasic().getAuthorizeMode();
if(mode != null && mode != SecurityAuthorizeMode.ROLE) {
if(mode == SecurityAuthorizeMode.AUTHENTICATED) {
((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
}
} else {
((AuthorizedUrl)http.authorizeRequests().anyRequest()).hasAnyRole(roles);
}
}
and you can also create a new configuration to override the default one.
@Configuration
// before the default configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 11)
class CustomH2ConsoleSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private H2ConsoleProperties console;
@Override
public void configure(HttpSecurity http) throws Exception {
String path = this.console.getPath();
String antPattern = (path.endsWith("/") ? path + "**" : path + "/**");
HttpSecurity h2Console = http.antMatcher(antPattern);
h2Console.csrf().disable();
h2Console.httpBasic();
h2Console.headers().frameOptions().sameOrigin();
// config as you like
http.authorizeRequests().anyRequest().permitAll();
}
}
Upvotes: 3
Reputation: 13
This also helps for me
#H2 database
datasource:
url: jdbc:h2:mem:mytestdb;INIT=RUNSCRIPT FROM 'classpath:/data.sql'
driverClassName: org.h2.Driver
username: sa
password: sa
main:
allow-bean-definition-overriding: true
h2:
console:
enabled: true
path: /h2-console
settings:
web-allow-others: true
allowed:
resources: /h2-console/**
security:
basic:
enabled: true
authorize-mode: NONE
Upvotes: 0
Reputation: 3542
I want to provide configuration similar to what is proposed by @argoth, but a bit more production ready :)
@Profile("h2") // to make sure it is active only if h2 profile is active
@Configuration
@ConditionalOnProperty( //to make sure it is active if console is enabled
value="spring.h2.console.enabled",
havingValue = "true",
matchIfMissing = false)
public class H2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// this may not be required, depends on your app configuration
http.authorizeRequests()
// we need config just for console, nothing else
.antMatchers("/h2_console/**").permitAll();
// this will ignore only h2-console csrf, spring security 4+
http.csrf().ignoringAntMatchers("/h2-console/**");
//this will allow frames with same origin which is much more safe
http.headers().frameOptions().sameOrigin();
}
}
In fact there was similar configuration done in boot 1.3 which was called H2ConsoleSecurityConfiguration, but now it's gone: Old class
Upd. very important note here! When you have multiple WebSecurityConfigurerAdapter
they may conflict with each other, so if you have another WebSecurityConfigurerAdapter
in your code, you will need to somehow merge them. To give you more details on why there will be a conflict, it will happen due to each adapter setting up it's own filter chain, and every request will have to pass both filter chains. If one of the chains forbids frameOptions and other doesn't the request won't pass the first chain.. That said, please, be careful with multiple configurers..
Upvotes: 5
Reputation: 1126
I enabled debug logging and saw this:
o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /h2-console/; Attributes: [hasAnyRole('ROLE_USER','ROLE_ACTUATOR')]
2017-05-05 13:16:09.304 DEBUG 90365 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@33d2af72: Principal: org.springframework.security.ldap.userdetails.LdapUserDetailsImpl@7371d5f4: Dn: cn=XYZ,ou=XYZ,ou=Active,ou=ABC_USERS,dc=internal,dc=organization,dc=com; Username: uname; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; CredentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 86EF50EF548ED4DBCE4D661AEC93F88C; Granted Authorities: ROLE_ADMIN
2017-05-05 13:16:09.305 DEBUG 90365 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@51d3d69, returned: -1
2017-05-05 13:16:09.305 DEBUG 90365 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
I realize that my user does not have the ROLE_USER
. I was assuming ROLE_ADMIN
> ROLE_USER
but I still need to understand this a little better.
I updated my settings to:
security:
basic:
enabled: true
authorize-mode: NONE
I am able to access the /h2-console/**
now.
Upvotes: 3