Search code examples
javaspring-security

Java Method Security Interceptor without adding Annotations to single Methods


i've tried in various ways to replicate the @PreAuthorize behaviour, so spel expression with a Method Invocation context: -I started with configuring httpSecurity in my WebSecurityConfigurerAdapter extending class with an access string written in spel, only to figure out the context was on Filter Invocation , so I had no access on the request body(which i need);

-implementing and adding a custom HandlerInterceptor to the InterceptorRegistry, but again the endpoint arguments were not accessible;

-extending ConfigGlobalMethodSecurity to create a custom expressionHandler, but I seems it is only triggered by Method-level annotations;

Can someone explain me if what i've trying to do is simply impossible or is there a way? I'd like to have the same evaluationContext as @PreAuthorize, so having access the method arguments(I mean the value they assume) using spel expressions and be able to configure it without having to annotate every single class or method.

EDIT

for reference these are the two annotations i'm using(and they work fine) the use i'm tring to replicate not by annotations but by configuration:

    @Target({ElementType.METHOD, ElementType.TYPE}) 
    @Retention(RetentionPolicy.RUNTIME)
    @PreAuthorize("hasAnyRole(@privilegeManager.privilegedRoles) or (@privilegeManager.verify(#id, this.getType()))")
    public @interface PathVariableRestriction {
    }

    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @PreAuthorize("hasAnyRole(@privilegeManager.privilegedRoles) or #dto.getOwnerId() == @myService.getCurrentId()")
    public @interface RequestBodyRestriction {
    }


Solution

  • i'd like to authorize request not based on roles but on ids: the id of the object being subject to the crud operation provided either as @PathVariable or @RequestBody(depends on if it is a get, post, put or delete) and the id of the current user retrieved through his Authentication

    This is one common use case for @PostAuthorize.

    For example if you do:

    @PostAuthorize("returnObject.username == authentication.name")
    @GetMapping("/resource/{id}")
    public MyResource getResource(String id) {
        // look up
        return myResource;
    }
    

    This will only return resources that belong to the currently authenticated user.

    This is the recommended route.

    able to configure it without having to annotate every single class or method

    Alternatively, you can build your own custom authorization method security from scratch using Spring Security's underlying components.

    Method Security is built on top of Spring AOP. This means that you can define your own pointcut instead of using Spring Security's annotation-based one. For example, you can do:

    @EnableMethodSecurity
    class SecurityConfiguration {
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        Advisor myMethodSecurityAdvisor() {
            Pointcut pointcut = myCustomPointcut();
            AuthorizationManager<MethodInvocationResult> rules = myRules();
            AuthorizationManagerAfterMethodInterceptor interceptor = 
                new AuthorizationManagerAfterMethodInterceptor(
                    pointcut, rules);
            interceptor.setOrder(AuthorizationInterceptorsOrder.
                POST_AUTHORIZE.getOrder() + 1);
            return interceptor;
        }
    }