javaspringspring-mvcspring-securityspring-security-acl

Spring Security ACL - Allow Users to 'read' one field from the Domain class


I'm very new to the Spring Security Framework and I have a little problem here to solve.

I've already managed to use the @PreAuthorized("hasPermission('#person', Permission) annotation for service and controller methods. This works fine for me, but this only works for the whole Domain class.

In my case there are some fields which should be shown to users despite they haven't the permission to read this Person.

A quick example:

  1. A user logs in.
  2. He'd like to visit the profile page from Jon Doe.
  3. But the user did not have the right to read Jon Doe.
  4. The System should notice the user that he hasn't the rights and shows the Name like: You doesn't have the permission to read the profile from Jon Doe."

This is a very simple example, there are more fields a user could see.

Hopefully you'll understand what I'm asking for.

(I´m sorry my english is not that good.)

EDIT

PersonController

 @RequestMapping("/{id}")
 public String get(@PathVariable("id") Long personId, Model model,HttpSession session) {

    Person person = personService.findById(personId);

    /* DO STUFF HERE */

    return "person.show";
}

PersonService

@PreAuthorize("hasPermission('#personId', <domainClass>, 'read')")
public Person findById(Long personId) {
    return personRepository.findOne(personId);
}

Solution

  • You could do it explicitely by no using @PreAuthorized("hasPermission('#person', Permission) annotation at all and instead doing it by hand in your code ... but that would partially defect the interest of using Spring Security framework !

    I would suggest :

    In that configuration, the exception handler should take parameters equivalent to original controller method to have access to :

    But this should not be a problem since an exception handler can accept almost the same parameters that a @RequestMapping method does in addition to the exception itself.

    Per your edit, you get the personId from a path variable, which would be hard to get from the exception handler. So you should save it as a request attribute before calling the protected service method to get it in the exception handler :

     @RequestMapping("/{id}")
     public String get(@PathVariable("id") Long personId, Model model,HttpSession session, HttpServletRequest request) {
    
        request.setAttribute("personId", personId);
        Person person = personService.findById(personId);
    
        /* DO STUFF HERE */
    
        return "person.show";
    } 
    
    @ExceptionHandler(AccessDeniedException.class)
     public ModelAndView accessDeniedHandler(HttpServletRequest request) {
        ModelAndView mav = new ModelAndView("accessDeniedView");
        Long personId = request.getAttribute("personId");
        // populate your model
        return mav;
    }