Describe the bug
When using @EnableGlobalMethodSecurity(prePostEnabled = true) alongside Spring Data REST, it is possible to add @PreAuthorize("hasRole('SOMETHING')") on the repository interface, which secures the entire repository. You can also use @PreAuthorize on individual methods
When using the newer @EnableMethodSecurity attribute, @PreAuthorize only works on individual methods, and does not work on an interface. This is a change in behavior that could result in potential accidental data leakage when upgrading to the latest Spring Security bits.
To Reproduce
- Wire up Spring Data REST in a project with
@EnableGlobalMethodSecurity(prePostEnabled = true) - Add
@PreAuthorize("hasRole('BOGUS')")to your repository interface - Make a GET request, observe that it is rejected
- Upgrade to
@EnableMethodSecurity - Make a request, observe that a response is returned instead of rejected. You are now leaking data to unauthorized callers
Expected behavior
@PreAuthorize to be processed the same way as before
Sample
https://github.com/noelbundick-msft/spring-security-methodsecurity-bug
Comment From: evgeniycheban
Hi @noelbundick-msft!
I've checked the sample you provided and I see that the findPreAuthorizeAnnotation performs search for @PreAuthorize annotation on the class that declares the called method in this case SimpleJpaRepository instead of $Proxy that implements repository interface.
This is definitely a bug, thanks for reporting.
The code I used to reproduce this:
@EnableMethodSecurity
// @EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class MethodSecurityConfig {}
@PreAuthorize("hasRole('BOGUS')")
public interface ThingRepository extends JpaRepository<Thing, Long> {
@Override
@PreAuthorize("hasRole('BOGUS')")
Optional<Thing> findById(Long id);
}
Thing testThing = new Thing();
testThing.setName("testName");
this.repository.save(testThing); // Should throw `AccessDeniedException` but it doesn't.
Comment From: rwinch
Thanks for the report, I closed this in favor of gh-11177