I followed the documentation on how to secure REST repositories with @PreAuthorize
. However, the following repository
@PreAuthorize("hasRole('ROLE_ADMIN')") @RepositoryRestResource public interface RouteRepository extends SortingOnlyRepository<Route, Long> { }
needs to be accessed by an ApplicationRunner
to perform some initial setup tasks after application startup.
@Component public class RouteBuilder implements ApplicationRunner { private final RouteRepository repository; public RouteBuilder(RouteRepository repository) { this.repository = repository; } @Override public void run(ApplicationArguments args) throws Exception { repository.findAll() .stream() // do something ; } }
Since there’s no security context active when this runner is executed the application won’t start at all
java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: java.lang.IllegalStateException: Failed to execute ApplicationRunner Caused by: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
What are my options to access the REST repository properly? I’m thinking of
- Populating a fake
Authentication
like this - Decouple concerns and just don’t use a REST repository for this use case
- Configure security in a
WebSecurityConfig
alone
Advertisement
Answer
The answer to the question is to populate a proper (fake) security context and is actually given in the official Spring Data REST + Spring Security example.
Adapted from Application
:
try { SecurityUtils.runAs("system", "system", "ROLE_ADMIN"); repository.findAll() .stream() // do something ; } finally { SecurityContextHolder.clearContext(); }
Where SecurityUtils
is
public static void runAs(String username, String password, String... roles) { SecurityContextHolder.getContext().setAuthentication( new UsernamePasswordAuthenticationToken(username, password, AuthorityUtils.createAuthorityList(roles))); }