Different credentials in Spring Boot application authentication and management authentication?
I want to use http basic authentication for my Spring Boot application with one set of credentials, and at the same time, I want to configure the executive to use a different set of credentials for management resources (health, env, etc.). I read the Actucator documentation, which says that you should be able to set username and password using properties security.user.name
and security.user.password
. However, when I add my custom one WebSecurityConfigurerAdapter
, it no longer applies. Mine WebSecurityConfigurerAdapter
looks like this:
@Configuration
@EnableWebMvcSecurity
@Order(Ordered.LOWEST_PRECEDENCE - 11)
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String API_USER = "API";
private static final String ADMIN_USER = "ADMIN";
@NotNull
@Value("${security.user.name}")
private String managementUsername;
@NotNull
@Value("${security.user.password}")
private String managementPassword;
@NotNull
@Value("${management.context-path}")
private String managementContextPath;
public ApplicationSecurityConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.securityContext().and()
.requestCache().and()
.servletApi().and()
.authorizeRequests()
.antMatchers(managementContextPath+"/**").hasRole(ADMIN_USER)
.antMatchers("/**").hasRole(API_USER)
.and()
.httpBasic();
// @formatter:on
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("apiUsername").password("apiPassword").roles(API_USER).
and().withUser(managementUsername).password(managementPassword).roles(ADMIN_USER);
}
}
I also tried to set management.security.enabled
on false
, but then the management resources seem to be open to everyone despite my efforts to protect it.
Does anyone know what I am doing wrong and how to do this?
Update
I see three Spring events selected from my application:
2015-06-10 20:04:37.076 INFO 44081 --- [nio-8083-exec-1] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Jun 10 20:04:37 CEST 2015, principal=<unknown>, type=AUTHENTICATION_FAILURE, data={type=org.springframework.security.authentication.AuthenticationCredentialsNotFoundException, message=An Authentication object was not found in the SecurityContext}]
2015-06-10 20:04:39.564 INFO 44081 --- [nio-8083-exec-2] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Jun 10 20:04:39 CEST 2015, principal=admin, type=AUTHENTICATION_SUCCESS, data={details=org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null}]
2015-06-10 20:04:39.569 INFO 44081 --- [nio-8083-exec-2] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Jun 10 20:04:39 CEST 2015, principal=admin, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]
But just two of the hyness example:
2015-06-10 19:34:10.851 INFO 42714 --- [nio-8083-exec-1] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Jun 10 19:34:10 CEST 2015, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]
2015-06-10 19:34:17.139 INFO 42714 --- [nio-8083-exec-2] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Jun 10 19:34:17 CEST 2015, principal=manage, type=AUTHENTICATION_SUCCESS, data={details=org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null}]
source to share
Hyness's answer worked if I changed:
..
.antMatchers(managementContextPath + "/**").hasRole(ADMIN_USER)
.antMatchers("/**").hasRole(API_USER)
to
..
.requestMatchers(request -> !request.getContextPath().startsWith(managementContextPath)).hasRole(API)
.antMatchers("/**").not().hasRole(API)
.antMatchers(managementContextPath + "/**").hasRole(ADMIN)
source to share
I changed the priority and changed the username and controlnames and it works for me. The control context is only available to the control user, and the rest of the protected paths are only available to apiUsername . The problem is that there are no basic logout functions. You need to close the browser window or use the closed tab to switch users.
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String API_USER = "API";
private static final String ADMIN_USER = "ADMIN";
@NotNull
@Value("${management.user.name}")
private String managementUsername;
@NotNull
@Value("${management.user.password}")
private String managementPassword;
@NotNull
@Value("${management.context-path}")
private String managementContextPath;
public ApplicationSecurityConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and().headers().and().sessionManagement()
.sessionCreationPolicy(STATELESS).and().securityContext().and()
.requestCache().and().servletApi().and().authorizeRequests()
.antMatchers(managementContextPath + "/**").hasRole(ADMIN_USER)
.antMatchers("/**").hasRole(API_USER).and().httpBasic();
// @formatter:on
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("apiUsername")
.password("apiPassword").roles(API_USER).and()
.withUser(managementUsername).password(managementPassword)
.roles(ADMIN_USER);
}
}
source to share
I am guessing that you would like to have different configurations for different urls? The chapter Multiple HttpSecurity in the Spring Security reference docs suggests creating a security configuration with multiple WebSecurityConfigurerAdapter
beans (simplified snippet based on your problem and example in the reference docs):
@Configuration
@EnableWebSecurity
public class MultiHttpSecurityConfig {
// variables omitted...
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("apiUsername").password("apiPassword")
.roles(API_USER).and()
.withUser(managementUsername).password(managementPassword)
.roles(ADMIN_USER);
}
@Configuration
@Order(1)
public static class ManagementWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher(managementContextPath+"/**")
.authorizeRequests()
.anyRequest().hasRole("ADMIN_USER")
.and()
.httpBasic();
}
}
@Configuration
public static class DefaultWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("API_USER")
.and()
.httpBasic()
}
}
}
Read more in the reference docs.
source to share