Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Securing @RequestBody

What is the proper way to secure the @RequestBody with Spring Security?

For example: A User can have multiple Blogs and each Blog can have multiple Entrys. A user goes to save an entry to a certain blog and the request would come in like this:

@RequestMapping(value="/api/entry", method=RequestMethod.POST)
@ResponseBody
public Entry save(@Valid @RequestBody Entry entry) {
    this.entryService.save(entry);
    return entry;
}

Now, the incoming entry has a Blog, the user could have doctored up the request and chosen someone else's blog, effectively posting the entry to their blog. Though I could catch this in validation (query the persistence layer to verify that the Blog belongs to the logged in User) I feel that this should be handled by Spring Security. If so, how do I go about doing this?

like image 739
Josh Johnson Avatar asked Sep 26 '12 23:09

Josh Johnson


1 Answers

We had this kind of situation.

Here is the two solution. I did not like much

@RequestMapping(value="/api/entry", method=RequestMethod.POST)
@ResponseBody
@PreAuthorize("#entry.author.name == principal.name)"
public Entry save(@Valid @RequestBody Entry entry, Principal principal) {
    this.entryService.save(entry);
    return entry;
} 

or

@RequestMapping(value="/api/entry", method=RequestMethod.POST)
    @ResponseBody
    @PreAuthorize("Decision.isOK(entry, principal)")
    public Entry save(@Valid @RequestBody Entry entry, Principal principal) {
        this.entryService.save(entry);
        return entry;
    }

//In that case Spring will call your static isOk() method from Decision class. It should return boolean.

Spring injects Principal principal authorized object for the method, you do not have to worry about it. Enable @PreAuthorize annotation with

<security:global-method-security pre-post-annotations="enabled" />

Second Using Aspect. Create aspect.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Protector {
}

@Aspect
@Component
public class MyAspect {
   @Before("@annotation(com.xyz.Protector)")
   public void before(JoinPoint joinPoint) throws Throwable {
        //u can get method object from joinPoint object, 
        Method method = ((MethodSignature)joinPoint.getMethodSignature()).getMethod();
        //As long as you have Method object you can read the parameter objects (Entry and Principal) with reflection. 
        //So Compare here: If entry.getOwner().getId().equal(principal.getName()) blah blah blah  
    }
}

@RequestMapping(value="/api/entry", method=RequestMethod.POST)
@ResponseBody
@Protector
public Entry save(@Valid @RequestBody Entry entry, Principal principal) {
    this.entryService.save(entry);
    return entry;
} 

If you have aspect you can have more owning on runtime

Also refer to this ulr

like image 94
Elbek Avatar answered Sep 27 '22 20:09

Elbek