We currently have different roles in our environments, for example in development we have roles called USR
and ADM
, while in production they use full names for example USER
, ADMIN
and ADMINISTRATOR
.
My idea to resolve this problem is to use a property file and a placeholder for the rolenames, for example, this is my properties file:
role.user='USER'
role.admin='ADMIN', 'ADMINISTRATOR'
In my AppConfig
I added the following annotation on top of the class:
@PropertySource("classpath:roles.properties")
public class AppConfig {
}
And in my service I'm now using:
@PreAuthorize("hasAnyRole(${role.admin})")
public Item deleteItem(int id) {
}
However, this results in the following exception:
Caused by: org.springframework.expression.spel.SpelParseException: EL1043E:(pos 12): Unexpected token. Expected 'rparen())' but was 'lcurly({)'
Because it says it's not expexting the curly brace, I also tried the following: @PreAuthorize("hasAnyRole(role.admin)")
which results in:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 11): Property or field 'role' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot' - maybe not public?
At least the expression itself looks valid now, but it seems it's not looking at the properties file no, but at a property of a specific class.
Does anyone have an idea to solve this? Or is there another/better solution of resolving environment-specific roles?
The Spring EL used in @PreAuthorize does only have:
Access to methods and properties of SecurityExpressionRoot.
Access method arguments (requires compilation with debug info or custom ParameterNameDiscoverer):
See this answer https://stackoverflow.com/a/3786581/883859
You can get access to other beans via @
so
public interface RoleNameGetter {
String getSuperUserRole();
...
}
And
@Configuration
@PropertySource("classpath:xyz.properties")
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class Configuration {
@Autowired
protected Environment env;
@Bean
RoleNameGetter roleNameGetter() {
return new RoleNameGetter() {
@Override
public String getSuperUserRole() {
return env.getProperty("superuser_role_name");
}
};
}
Allows for access to role names from the property file in the Spring EL used in @PreAuthorize, like this:
@PreAuthorize("hasAnyAuthority(@roleNameGetter.getSuperUserRole(),@roleNameGetter.getNormalUserRole())")
public void end() {...}