1

Can We use Spring Security's @PreAuthorize, @PostAuthorize, @PreFilter or @PostFilter on JPA's @Entity methods?

Only recommendations/answers I found are 6+ year old threads and usually say "Use service layer" and sometimes "controllers can also have security annotations, but service layer is more straightforward".

Noone every talks about using security annotations on @Entity.

To explain simple use case: Say we have 3 Spring's JpaRepositories for Person and Group and Party:

@Entity
class Person {
    ...
    @ManyToOne
    Group group;
    @ManyToOne
    Party party;
}

@Entity
class Group {
    ...
    @OneToMany
    List<Person> people;
    @ManyToOne
    Party party;
}

@Entity
class Party {
    ...
    @OneToMany
    List<Person> people;
    @OneToMany
    List<Group> groups;
}

So basically - one person can belong to one group and at the same time to one party. One group can also belong to one Party and has many people. And one party consists of many groups and many separate people (that might or might not be in groups).

Lots of code, like mappedBy, ids and getters/setters/adders/removers were omitted for brevity.

If I could secure Entity methods, i can do:

@Entity
class Party {
    ...
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    List<People> getPeople() { return this.people; }
}

@Service
class PartyService {
    @Autowired
    PartyRepository repo;

    List<People> getPeople(Long partyId) {
        return repo.getById(partyId).getPeople(); // Should either return people or throw access exception.
    }
}

@Service
class GroupService {
    @Autowired
    GroupRepository repo;

    List<People> getPeopleInMyParty(Long groupId) {
        return repo.getById(groupId).getParty().getPeople(); // Should either return people or throw access exception.
    }
}

If I cant secure Entity method, it leaves me with going through services, like:

@Entity
class Party {
    ...
    // Not secured here
    List<People> getPeople() { return this.people; }
}

@Service
class PartyService {
    @Autowired
    PartyRepository repo;

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    List<People> getPeople(Long partyId) {
        return repo.getById(partyId).getPeople(); // Should either return people or throw access exception.
    }
}

@Service
class GroupService {
    @Autowired
    GroupRepository repo;
    @Autowired
    PartyService partyService;

    List<People> getPeopleInMyParty(Long groupId) {
        return partyService.getPeople(repo.getById(groupId).getParty().getId()); // Should either return people or throw access exception.
    }
}

This poses complications in my much more sophisticated JPA data model (and its fetching service) as We get more and more @Service and @Repository injections all over the place and code becomes confusing to maintain. Look at difference between GroupService between 2 examples - if You scale that up, You'll get TONS of IDs and injections to all related services, instead of just doing @Entity method calls.

So can I do it at @Entity level and how to enable it?

Ernio
  • 948
  • 10
  • 25

1 Answers1

0

This problem/question produced another question to which answer also solves this one.

Basically I first found out that Spring Security supports AspectJ out-of-box (ships with @Aspect in one of sub-projects) and after some configuration managed to set it up, effectively being able to @Secure (and other security annotations) my @Entity classes.

Enabling compile-time AspecJ for Spring Method Security

Ernio
  • 948
  • 10
  • 25