21

I am using Spring Security for permission checking on methods. I would like to call a private method to collect some data to send to hasPermission() method. Following is something I am trying to execute and I get SpelEvaluationException because Spring is looking for the localPrivateMethod in MethodSecurityExpressionRoot. Is there a way to achieve this? Thanks.

@PreAuthorize("hasPermission(new Object[]{#arg3, #localPrivateMethod(#arg1,#arg2)}, 'canDoThis')")  
public long publicMethod1(long arg1, long arg2, long arg3) {}

private String localPrivateMethod(long a1, long a2) {}
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
M99
  • 1,859
  • 10
  • 28
  • 50
  • the general idea here: http://stackoverflow.com/questions/13564627/spring-aop-not-working-for-method-call-inside-another-method – Muhammad Hewedy Jan 19 '16 at 21:59

3 Answers3

41

You will not be able to call a private method, but you will be able to call a method in another spring bean. In my app I have an @Component named permissionEvaluator. I then reference it in a @PreAuthorize like so:

@PreAuthorize("@permissionEvaluator.canViewImageSet( #imageSet, principal )")
@RequestMapping(value="/image", method=RequestMethod.GET )
public String getImage(
        @RequestParam(value="imageSet", required=false) ImageSet imageSet ) {
    // method body
}

PermissionEvaluatorImpl looks like this:

@Component(value="permissionEvaluator")
public class PermissionEvaluatorImpl implements PermissionEvaluator
{
    public PermissionEvaluatorImpl() {}

    /**
     * Determine if a user can view a given image.
     */
    public boolean canViewImageSet( ImageSet imageSet, UserDetailsAdapter user )
    {
        // code to see if they should view this image
    }
}

and PermissionEvaluator is my own interface with nothing special, just whatever methods I need to evaluate.

digitaljoel
  • 26,265
  • 15
  • 89
  • 115
  • I spent a complete hour investigating similar problem and when I see your answer I remember that spring apply interceptors for proxies on other classes, when calling methods in same classes proxies couldn't be applied http://stackoverflow.com/questions/13564627/spring-aop-not-working-for-method-call-inside-another-method – Muhammad Hewedy Jan 19 '16 at 21:58
  • Do you need to do anything else? I tried exactly that and it won't work. – Tim Oct 18 '16 at 10:33
  • If your permissionEvaluator is a bean then you should be fine. If you are manually setting up your beans instead of using component scanning then you will have to ensure the permissionEvaluator bean exists. – digitaljoel Oct 18 '16 at 19:31
  • 2
    PermissionEvaluator is an existing Spring Security interface, at least it is in spring security core 5.1.5 So this code wont work because you are not implementing the methods from PermissionEvaluator. And if you don't intend to use PermissionEvaluator than I'd suggest renaming your custom interface. – Igorski May 19 '19 at 10:22
  • I noticed that we need to qualify the bean in order to @PreAuthorize. Anyone knows why ? – Viraj Nimbalkar Jul 22 '19 at 16:55
4

Private methods cannot be called, but you can refer to "this component" through this.:

@PreAuthorize("hasPermission(new Object[]{#arg3, /* HERE: */ this.localPublicMethod(#arg1,#arg2)}, 'canDoThis')")   
public long publicMethod1(long arg1, long arg2, long arg3)
{
}

public String localPublicMethod(long a1, long a2)
{
}
Mateusz Stefek
  • 3,478
  • 2
  • 23
  • 28
0

It can be done in simple way using @someController.localPublicMethod(#arg1,#arg2)

no need to implement permissionEvaluator

@RestController
public class SomeController{

@PreAuthorize("hasPermission(new Object[]{#arg3, @someController.localPublicMethod(#arg1,#arg2)}, 'canDoThis')")  
public long publicMethod1(long arg1, long arg2, long arg3) {}

public String localPublicMethod(long a1, long a2) {}

}
}

localPublicMethod cannot be private

For Permission evaluator - There is better way to do it one can refer below link https://www.baeldung.com/spring-security-create-new-custom-security-expression