Brett Ryan
Brett Ryan

Reputation: 28305

What is the correct approach for denying access to specific resources in spring MVC + security

I've seen many questions requesting how to handle security scenarios, all either have solutions for method annotations (i.e. @PreAuthorize("hasRole('ROLE_USER')")) or using a point-cut.

However what if the resource isn't known if the user has access until the resource has been read from a data store? Let's consider a user who has access to a set of customers, the rest endpoint for these customers can be found at /customers/{id}. A user is only allowed access if they have been granted access to read the account, likewise they must also have access to make a POST to the same endpoint.

One way would be:

@RequestMapping(value = "/customers/{id}", method = RequestMethod.GET)
public ModelAndView customerPage(String id, HttpServletRequest req, Principal principal) {
    if (!req.isUserInRole("ROLE_ADMIN") && !cs.accessGranted(id, principal.getName())) {
        throw new AccessDeniedException("You do not have access to view this custoemr.");
    }
    Customer cust = cs.getCustomer(id);
    if (cust == null) {
        throw new ResourceNotFoundException("Customer does not exist!");
    }
    ModelAndView mov = new ModelAndView("customers/info");
    mov.addObject("customer", cust);
    return mov;
}

I'm wondering if this is the right approach though.

UPDATE: Call to accessGranted was meant to have id as an argument which I missed.

Upvotes: 1

Views: 189

Answers (2)

Maksym Demidas
Maksym Demidas

Reputation: 7817

There is a way to continue use @PreAuthorize annotations. You can call beans directly from SpEL expression:

@PreAuthorize("hasRole('ROLE_USER') and [email protected](#principal.getName())")
public ModelAndView customerPage(String id, HttpServletRequest req, Principal principal) {

@cs refers to bean id = "cs" declared somwhere in your application context. Later you can future simplify it by removing Principal principal method parameter and getting username directly in SpEL.

If your find yourself using this tehnique often then check out Spring Security ACL module.

Upvotes: 1

CodeChimp
CodeChimp

Reputation: 8154

My favorite way is to use the @Secured annotation on a method, which takes an array of Strings representing the Role(s) required to execute the method. I like this method because you are not limited to putting security only on URL patterns. For instance, you can add this to a method in your Service class, and any Controller using that Service is now secured.

The other common method is to include URL filters in the Spring Security XML file. I forget the exact syntax, but you basically setup filters that match a URL and indicate what Role(s) are needed.

Upvotes: 0

Related Questions