'Custom security expression root not working on docker
I have problem with working with custom spring security expressions in Docker.
I have functionality for using custom expressions in @PreAuthorize functions.
@PreAuthorize("hasAuthority('cashmanagement_reports') AND isAccountsBelongsToCustomerAsMonitoringType(#filter)")
Also I have MethodSecurityConfig
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
LOG.info("Started creating expression handler for security");
CustomMethodSecurityExpressionHandler expressionHandler =
new CustomMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
expressionHandler.setApplicationContext(applicationContext);
return expressionHandler;
}
}
and CustomMethodSecurityExpressionHandler
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private ApplicationContext applicationContext;
public CustomMethodSecurityExpressionHandler() {
super();
}
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
LOG.info("Started creating expression root for security");
CustomMethodSecurityExpressionRoot root =
new CustomMethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
super.setApplicationContext(applicationContext);
this.applicationContext = applicationContext;
}
And CustomMethodSecurityExpressionRoot class
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
@Getter
private Object filterObject;
@Getter
private Object returnObject;
@Getter
@Setter
private Object target;
@Setter
private IUserUtils userUtils;
@Setter
private MonitoringRequestDao monitoringRequestDao;
@Setter
private ClassifierDao classifierDao;
@Setter
private MonitoringAccountDao monitoringAccountDao;
@Setter
private TransferRequestDao transferRequestDao;
public CustomMethodSecurityExpressionRoot(Authentication a) {
super(a);
}
@Override
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
@Override
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
/**
* Sets the "this" property for use in expressions. Typically this will be the "this"
* property of the {@code JoinPoint} representing the method invocation which is being
* protected.
*
* @param target the target object on which the method in is being invoked.
*/
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
/**
* Returns true if user is belongs to {@link MonitoringRequest} as child organization
*
* @param monitoringRequestId {@link MonitoringRequest#getId()}
* @return true if user is the member of {@link Customer}, else false
*/
public boolean isAccountsBelongsToCustomerAsMonitoringType(ReportFilter) {
.....
}
All is working OK, if I run using IntellijIDEA. But when I run service using docker image, I am getting this error.
Failed to evaluate expression 'hasAuthority('cashmanagement_reports') AND isAccountsBelongsToCustomerAsMonitoringType(#filter)'
java.lang.IllegalArgumentException: Failed to evaluate expression 'hasAuthority('cashmanagement_reports') AND isAccountsBelongsToCustomerAsMonitoringType(#filter)'
.............................
..............................
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method isAccountsBelongsToCustomerAsMonitoringType(com.infin.it.ibank.dto.ReportFilter) cannot be found on org.springframework.security.access.expression.method.MethodSecurityExpressionRoot type
Solution 1:[1]
Adding proxyTargetClass to EnableGlobalMethodSecurity annotation helped me.
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler expressionHandler =
new CustomMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
expressionHandler.setApplicationContext(applicationContext);
return expressionHandler;
}
}
UPDATE
The problem reappears. I decided to remove custom expressions.
Solution 2:[2]
I had the same issue while upgrading to Spring Boot 2.6 (from 2.3) on a project using OAuth2.
It appears that recent versions of Spring Boot Security OAuth2 declare a MethodSecurityExpressionHandler
bean (in OAuth2MethodSecurityExpressionHandlerConfiguration
) if there isn’t already one. This bean gets injected into GlobalMethodSecurityConfiguration.setMethodSecurityExpressionHandler()
, which prevents createExpressionHandler()
from being called.
To fix this, createExpressionHandler()
should be annotated with @Bean
, and you don’t need to extend GlobalMethodSecurityConfiguration
any more:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig {
@Autowired
private ApplicationContext applicationContext;
@Bean
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler expressionHandler =
new CustomMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
expressionHandler.setApplicationContext(applicationContext);
return expressionHandler;
}
}
This, of course, disables the OAuth2MethodSecurityExpressionHandler
, so you won’t be able to use expressions such as #oauth2.clientHasRole('ROLE_ADMIN')
. I suppose it should be possible to combine the two but I didn’t need it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Didier L |