Let's say I've a minimal RESTful controller like the following, by the way using Java 8 and Spring Boot 2, ...
@RestController
class MyController {
@Autowired
private PostService service;
@GetMapping
public Post get() {
return service.getLatest();
}
}
I've secured this route successfully using the Spring Security module. Now I want to allow only the resource owner access to this resource. With resource owner I mean the creator or saying it simple:
Post myPost = new Post();
...
myPost.getCreator().equals(currentUser); // Should be true when access is granted
I found a lot about role based access, but nearly nothing for checking ownership... Of course I could place an if statement inside of the controller and throw an exception, but I intended to use something like Spring's Expression-Based Access Control.
Any other ideas? Does somebody have a good idea or example for ownership checking of a resource?
For a simple get operation you can just return the post linked to your current logged in user
@GetMapping
public Post getPost(Authentication authentication) {
return service.getPostByUser(authentication.getName());
}
For updating an existing post, you can check within the PreAuthorize if the creator is the logged in user. authentication.getName() gives back an email in my example
@PutMapping
@PreAuthorize("#post.getCreator() == authentication.getName()")
public void update(@RequestBody Post post, Authentication authentication) {
service.updatePost(post);
}
Basic example of the @Component way
@Autowired
private CreatorCheck creatorCheck;
@PutMapping
@PreAuthorize("@creatorChecker.check(#post,authentication)")
public void update(@RequestBody Post post, Authentication authentication) {
service.updatePost(post);
}
And the component.. Can be extended to retrieve the original Post and check that creator..
@Component
public class CreatorCheck {
public boolean check(Post post, Authentication authentication) {
return post.getCreator().equals(authentication.getName());
}
}
For a more comprehensive tutorial check out this tutorial link found by 0x1C1B
But this means the client is setting the post's creator inside the request right? How can I prevent that it manipulates the creator? Let's say using it's own id to grant access... Or for an DELETE request, theres no DTO/payload given as argument...
You could write another @Component public CreatorChecker class to handle the checks. @PreAuthorize("@creatorChecker.check(#post,authentication)") In this component you retrieve the post from the DB and check the creator service.getPostId().getCreator() == authentication.getName() like that
Where is this component used? As part of the filter chain? Is this a common aproach I found nothing like this... But seems to be an interessting solution
It will get evaluated the same way as some default stuff such as hasRole('FOO') as it just a different expression that needs to evaluated. Spring Docs Link
That's my favorite solution... I found a basic example about using external components for authorization. Could you update your answer so I can accept it?