spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.75k stars 5.87k forks source link

property permissionEvaluator of DefaultMethodSecurityExpressionHandler is always DenyAllPermissionEvaluator in child application context #4059

Open toughpheeckouse opened 8 years ago

toughpheeckouse commented 8 years ago

spring-security version 4.1.3.RELEASE

I have root application context and I created a new child context while initializing root context. Root context has configuration bean GlobalMethodSecurityConfiguration:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration
{
... 
    @Bean
    public MutableAclService aclService()
...
    }

    @Bean
    public PermissionEvaluator permissionEvaluator(AclService aclService)
    {
        return new AclPermissionEvaluator(aclService);
    }
...
}

while root context initializing created a new child context

migrationContext = new AnnotationConfigApplicationContext();

            migrationContext.setParent(applicationContext);

in child context created beans which call some protected methods with PreAuthorize("hasPermission(...)") annotation but I always get AccessDeniedException because root context is in initializing method GlobalMethodSecurityConfiguration.afterSingletonsInstantiated is not called yet and expression evaluator uses default permission evaluator DenyAllPermissionEvaluator but expected to be used AclPermissionEvaluator.

Before changes in afterSingletonsInstantiated method GlobalMethodSecurityConfiguration configures defaultMethodExpressionHandler correct autowired permission evaluator (AclPermissionEvaluator).

How to correct configure GlobalMethodSecurityConfiguration before child context will be create?

maurociancio commented 6 years ago

Hi there, I'm facing the same issue. How did you solve it? Thanks!

toughpheeckouse commented 6 years ago

@maurociancio, GlobalMethodSecurityConfiguration has protected method createExpressionHandler. I've overrided it and set correct PermissionEvaluator:

@Override
    protected MethodSecurityExpressionHandler createExpressionHandler()
    {
        MethodSecurityExpressionHandler expressionHandler = super.createExpressionHandler();

        if (expressionHandler instanceof DefaultMethodSecurityExpressionHandler)
        {
            DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler
                = (DefaultMethodSecurityExpressionHandler)expressionHandler;

                defaultMethodSecurityExpressionHandler.setPermissionEvaluator(permissionEvaluator);
        }
        else
        {
            logger.warn("MethodSecurityExpressionHandler is not instance of DefaultMethodSecurityExpressionHandler.");
        }

        return expressionHandler;
    }

If you'll get more beautiful solution, share it please

maurociancio commented 6 years ago

yes! i've ended up using the same approach. Thanks for your reply!