Is there a way I can disable the global method security using the boolean securityEnabled from my config.properties? Any other approach?
@EnableWebSecurity
I've managed this by defining a Spring "securityDisabled" profile and conditionally applying security config based off that. I'm using Spring Boot 2.0.2. I believe this should work if not using Spring Boot and in previous versions of Spring Boot, but I have not tested. It's possible some tweaks may be required to property and class names because I know in Spring 2.0 some of that changed.
// In application.properties
spring.profiles.include=securityDisabled
Then my security config looks like this:
@Configuration
public class SecurityConfig {
// When the securityDisabled profile is applied the following configuration gets used
@Profile("securityDisabled")
@EnableWebSecurity
public class SecurityDisabledConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// Configure http as needed from Spring Security defaults when
// NO security is desired
}
}
// When the securityDisabled profile is NOT applied the following configuration gets used
@Profile("!securityDisabled")
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityEnabledConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// Configure http as needed from Spring Security defaults when
// security is desired
}
}
}
Thanks to Rob Winch for the solution. For folks who would like to do something similar but with prePostEnabled i have tried and tested the below similar approach and works just fine.
@EnableGlobalMethodSecurity(securedEnabled = true)
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Value("${security.prePostEnabled}")
private boolean prePostEnabled;
@Autowired
private DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return prePostEnabled ? new PrePostAnnotationSecurityMetadataSource(new ExpressionBasedAnnotationAttributeFactory(defaultMethodSecurityExpressionHandler)) : null ;
}}
EDIT: In addition to above i realized it is required to add following beans to the class. The below will help using the expression based pre invocation checks along with avoiding "ROLE_" prefix that is defaulted in all the handlers
protected AccessDecisionManager accessDecisionManager() {
AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
//This is required in order to allow expression based Voter to allow access
accessDecisionManager.getDecisionVoters()
.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
//Remove the ROLE_ prefix from RoleVoter for @Secured and hasRole checks on methods
accessDecisionManager.getDecisionVoters().stream()
.filter(RoleVoter.class::isInstance)
.map(RoleVoter.class::cast)
.forEach(it -> it.setRolePrefix(""));
return accessDecisionManager;
}
/**
* Allow skip ROLE_ when check permission using @PreAuthorize, like:
* @PreAuthorize("hasAnyRole('USER', 'SYSTEM_ADMIN')")
* Added all the Beans
*/
@Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
defaultMethodSecurityExpressionHandler.setDefaultRolePrefix("");
return defaultMethodSecurityExpressionHandler;
}
The easiest way to do this is:
For example:
@EnableWebSecurity
@Configuration
@PropertySource("classpath:config.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}
@EnableGlobalMethodSecurity
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Value("${securityconfig.enabled}")
private boolean securityEnabled;
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return securityEnabled ? new SecuredAnnotationSecurityMetadataSource() : null;
}
}