Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relax Security for a Spring Data REST Projection

I have a User class and I want to authorize access such that only a user gets to see what he is entitled to.

This was easily achievable using Spring Security in conjunction with Spring Data Rest where in JPA Repository I did below -

public interface UserRepository extends JPARepository<User,Integer> {

    @PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")
    User findOne(@Param("id") Integer id);

}

In this way, a user when visits to Spring Data REST scaffolded URLs like -

/users/{id}
/users/{id}/userPosts

Only those logged in with {id} get to see these and everyone else gets 401 like I would have wanted.

My problem is that I have one of Projections which is a public view of each user and I am crating it using Spring Data Rest projections as below which I want to be accessible for every {id}

@Projection(name = "details", types = User.class)
public interface UserDetailsProjection {
..
}

So, /users/{id1}?projection=details as well as /users/{id2}?projection=details should give 200 OK and show data even though user is logged in by {id1}

I began implementing this by marking projection with @PreAuthorize("permitAll") but that won't work since Repository has harder security check. Can we have this functionality where for a projection we can relax security ?

I am using latest Spring Data Rest and Spring Security distributions

like image 570
fortm Avatar asked Nov 01 '22 09:11

fortm


1 Answers

Seems reasonable to add a custom controller for this use-case.

Please also consider:

  • Evaluate access in projections using @Value annotations
  • Add another entity for the same database data but with different field set for read-only operations, e.g. using inheritance (be careful with caching, etc.) - depends on your data storage type
  • Modify model to split User entity into two different entities (profile, account) since they seem to have different access and possibly even operations
  • You can also add a ResourceProcessor<UserSummaryProjection> to evaluate access programmatically and replace resource content (projection) with a DTO

Example of evaluating access in projections with @Value annotations:

@Projection(types = User.class, name = "summary")
public interface UserSummaryProjection {
  @Value("#{@userSecurity.canReadEmail(target) ? target.email: null}")
  String getEmail();
}
like image 143
aux Avatar answered Nov 15 '22 07:11

aux