Question

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...

Was it helpful?

Solution

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).

OTHER TIPS

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.

For future users:

As per @Dave Syer suggestion issue was using new keyword changing new MyPermissionEvaluator() to @Autowired will solve the issue as shown below.

changing below code

From:

@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;
    }
}

To:

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

 @Autowired
 private MyPermissionEvaluator myPermissionEvaluator;

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {

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

        return expressionHandler;
    }
}

with the above change below code will start working as expected.

@Autowired
    private UserRepository userRepo;

Solutions from Dave Syer & SchonWieder works for me. As alternative I want to show, how I solved this problem before. I inject Permision Evaluator in MethodSecurityConfig like anonymous class.

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

    @Autowired DataSource dataSource;

    @Override    
    protected MethodSecurityExpressionHandler createExpressionHandler() {
       DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
       expressionHandler.setPermissionEvaluator(new PermissionEvaluator(){

            @Override
            public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) {
                    
                    JdbcTemplate template = new JdbcTemplate(dataSource);
                    ... 
                    if (count==1){
                        return true;
                    } else {
                        return false;            
                    }
                }

            @Override
            public boolean hasPermission(Authentication arg0, Serializable arg1, String arg2, Object arg3) {
                    // TODO Auto-generated method stub
                    return false;
                }
                
            });
            return expressionHandler;
        }
}

  

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top