Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repository access control in Spring Data Rest based off user princpal

I'm attempting to implement fine grain access control while still taking advantage of Spring data rest.

I'm working on securing a CrudRepository so users can only modify or insert data that belongs to them. I'm making use of @PreAuthorize/@PostAuthorize and @PreFilter/@PostFilter to lock access down to the current principal.

So far my repository looks like this.

public interface MyRepository extends CrudRepository<MyObject, Integer> {

    @PreAuthorize("#entity.userId == principal.id")
    @Override
    <S extends MyObject> S save(S entity);

    @PreFilter("filterObject.userId === principal.id")
    @Override
    <S extends MyObject> Iterable<S> save(Iterable<S> entities);

    @PostAuthorize("returnObject.userId == principal.id")
    @Override
    MyObject findOne(Integer integer);

    @PostFilter("filterObject.userId == principal.id")
    @Override
    Iterable<MyObject> findAll();

}

While this is a bit tedious, it does seem to accomplish what I'm after. (If anyone knows a better way, feel free to let me know!)

Where I'm running into problems is with delete(), count() and exists()

    @Override
    long count();

    @Override
    void delete(Integer integer);

    @Override
    void delete(MyObject entity);

    @Override
    void deleteAll();

    @Override
    boolean exists(Integer integer);

These methods either take an Integer ID parameter or none at all. It seems like I would have to first select the entity with the input ID and then perform the auth check.

Is this type of authorization possible within the repository?

Thanks

Edit:

Thanks to ksokol this seems to be working now.

I added a new bean to a @Configuration class

@Bean
public EvaluationContextExtension securityExtension() {
    return new SecurityEvaluationContextExtensionImpl();
}

This bean extends EvaluationContextExtensionSupport and overrides getRootObject to return a SecurityExpressionRoot that holds my custom principal.

public class SecurityEvaluationContextExtensionImpl extends EvaluationContextExtensionSupport {
@Override
public String getExtensionId() {
    return "security";
}

@Override
public Object getRootObject() {
        Authentication authentication =   SecurityContextHolder.getContext().getAuthentication();
        return new SecurityExpressionRoot(authentication){};
    }
}
like image 272
francis Avatar asked Apr 17 '15 00:04

francis


1 Answers

Can also be achieved by implementing your checks in your custom Spring repository event handlers. See @HandleBeforeCreate, @HandleBeforeUpdate, @HandleBeforeDelete.

Alternatively, you can use permission-based expressions, e.g. with ACL or your custom ones, you can write @PreAuthorize("hasPermission(#id, 'MyObject', 'DELETE')").

like image 62
aux Avatar answered Nov 10 '22 01:11

aux