What is the proper way to secure the @RequestBody
with Spring Security?
For example: A User
can have multiple Blog
s and each Blog
can have multiple Entry
s. 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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With