Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Autowired in Spring PermissionEvaluator

First off I have googled this extensively and while it appears that there is supposedly a fix in place I cannot successfully reference an injected @Bean inside of a PermissionEvaluator:

https://jira.springsource.org/browse/SEC-2136?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel

In that issue's comments section Rob Winch provides a work around suggestion

to work around this issue, you can proxy your permissionEvaluator using LazyInitTargetSource

That being said, I am having trouble implementing the annotation-based JavaConfig version of the posted XML. I am using Spring Boot 1.0.0.BUILD-SNAPSHOT and spring-boot-starter-security.

I have a class to configure method security as follows:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {                   

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {

        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(new MyPermissionEvaluator());
        expressionHandler.setParameterNameDiscoverer(new SimpleParameterDiscoverer());

        return expressionHandler;
    }
}

And the start of a PermissionEvaluator:

public class MyPermissionEvaluator implements PermissionEvaluator {

    private static final Logger LOG = LoggerFactory.getLogger(MyPermissionEvaluator.class); 

    @Autowired
    private UserRepository userRepo;    

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {     

    if (authentication == null || !authentication.isAuthenticated()) {
        return false;
    }

    if (permission instanceof String) {

        switch((String) permission) {

        case "findUser":
            return handleUserPermission(authentication, targetDomainObject);

        default:
            LOG.error("No permission handler found for permission: " + permission);             
        }           
    }

    return false;
}

@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {

    throw new RuntimeException("Id-based permission evaluation not currently supported.");
}

private boolean handleUserPermission(Authentication auth, Object targetDomainObject) {

    if (targetDomainObject instanceof Long) {           

        boolean hasPermission = userRepo.canFind((Long) targetDomainObject);

        return hasPermission;
    }

    return false;
}

}

What needs to be done so that I can get a reference to my UserRepository from inside the PremissionEvaluator? I've attempted various workarounds w/ no success. It seems that nothing can be @Autowired into the PermissionEvaluator...

like image 924
Ethan Anderson Avatar asked Feb 18 '14 22:02

Ethan Anderson


2 Answers

Nothing can be autowired into an object that is created with new ...() (unless you are using @Configurable and AspectJ). So you almost certainly need to pull your PermissionEvaluator out into a @Bean. If you need to make it a lazy proxy as well (because of the ordering sensitivity of Spring Security initialization), then you should add @Lazy @Scope(proxyMode=INTERFACES) (or TARGET_CLASS if that suits you better).

like image 120
Dave Syer Avatar answered Sep 22 '22 21:09

Dave Syer


I had the same issue and the answer from Dave Syer worked perfectly for me. To respond to the comment from jasonfungsing, to pull the PermissionEvaluator into a Bean I annotated my custom class with @Component and @Autowired the DAO into it:

@Component
public class CustomPermissionEvaluator implements PermissionEvaluator{

private CustomRepository customRepository;

@Autowired
public void setCustomRepository(CustomRepository customRepository) {
    this.customRepository = customRepository;
}

@Override
public boolean hasPermission(Authentication authentication, Object target, Object permission) {

    if (target instanceof ...

Then in my GlobalMethodSecurityConfiguration overriding class I created a private instance variable of my PermissionEvaluator class, @Autowired the PermissionEvaluator into it and used this instance in my setPermissionEvaluator method call (thus avoiding a "new" call):

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{

private DataSource datasource;
private CustomPermissionEvaluator customPermissionEvaluator;

@Autowired
public void setCustomPermissionEvaluator(CustomPermissionEvaluator customPermissionEvaluator) {
    this.customPermissionEvaluator = customPermissionEvaluator;
}    
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
    DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
    expressionHandler.setPermissionEvaluator(customPermissionEvaluator);
    return expressionHandler;
}

I did not need to use the @LAZY or @SCOPE annotations.

like image 29
SchonWieder Avatar answered Sep 26 '22 21:09

SchonWieder