1

I want to allow only a specific user to access their modification page.

For example, I want user 3 to be the only one to able access the url : /user/3/edit

For this, I have put in my SecurityConfiguration.java :

.authorizeRequests()
.antMatchers("/user/{id}/edit").access("@MyClass.checkId(#id)");

MyClass.java is the following:

@Component
public class MyClass{


    public boolean checkId(Long id) {
        if(id == SecurityUtils.getCurrentUserId()){ //I have this configured and working
            return true;
        }
        return false;
    }
}

Yet when go to the following url: user/4/edit logged in as user 3 (these are examples), I cannot seem to enter the checkId method, and nothing happens, and my page loads with everything in it.

Do you have any idea? Is antMatchers.access() the way to go?

Thank you for your time!

Andre Debuisne
  • 303
  • 1
  • 3
  • 15

2 Answers2

1

You'll need to subclass two classes.

First, set a new method expression handler

<global-method-security>
  <expression-handler ref="myMethodSecurityExpressionHandler"/>
</global-method-security>

myMethodSecurityExpressionHandler will be a subclass of DefaultMethodSecurityExpressionHandler which overrides createEvaluationContext(), setting a subclass of MethodSecurityExpressionRoot on the MethodSecurityEvaluationContext.

For example:

@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
    MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
    MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth);
    root.setTrustResolver(trustResolver);
    root.setPermissionEvaluator(permissionEvaluator);
    root.setRoleHierarchy(roleHierarchy);
    ctx.setRootObject(root);

    return ctx;
}
Akash
  • 587
  • 5
  • 12
  • 2
    Thank you for the answer, though this seems to be a copy-paste of this answer: https://stackoverflow.com/a/6634438/5749754, word for word which is not cool for not even mentionning it! But thank you at least I found what I was looking for... – Andre Debuisne Aug 16 '17 at 20:45
0

There is another solution and it can be accomplish in a very elegant way using Expression-Based Access Control, for this case you can use the @PreAuthorize annotation and inside it validate the principal user id. For example:

  @PreAuthorize("#id == principal.userNumber")
  @RequestMapping(method = RequestMethod.POST, value = "/user/{id}/edit")
  public void userUpdate(Long id){ .. }

Please just make sure that the implementation of the UserDetails interface has the userNumber property.

You can see more information about Expression-Based Access Control

Another approach is to inject the Principal object into the Request handler method like this:

@RequestMapping(method = RequestMethod.POST, value = "/user/{id}/edit")
public void userUpdate(Long id, Principal myPrincipal){ 

  MyUserDetails user = (MyUserDetails) myPrincipal;
  if (user.getUserNumber == id) { ... }
    ....
}
Daniel C.
  • 5,418
  • 3
  • 23
  • 26