I'm migrating a microservice built on Spring Boot from Spring Security OAuth 2 (2.5.5) to Spring Security 5. For resource servers, this is easily done following many of the tutorials found online.
Problem arises when there's Authorization server logic, which is not directly supported by Spring Security 5. Recently Spring has made available a production-ready version of their new Auth server, Spring Authorization Server 0.2.0. This components follows the same coding style and structure of Spring Security OAuth 2, but there is no documentation available yet, and very few tutorials online available.
While this microservice is not a proper authorization server, it uses Spring auth server code to generate a custom authenticationProvider
for our local environment that can return a OAuth2Authentication
(deprecated) authentication token, all of this configuration is defined in a ResourceServerConfigurerAdapter
(which is also deprecated).
This was done so that we can test endpoints in our local environment without the need of a JWT, and by having a OAuth2Authentication
we don't need to make any changes in our code, if we ever need to get any claims from the JWT in the code. I haven't seen this kind of setup online, and I haven't been able to properly create an authenticationProvider
using Spring Authorization Server's classes. I always get a 403 response from any endpoint.
Original code with Spring Security OAuth 2
@EnableResourceServer
@Configuration
@Profile("local")
public class ResourceServerConfigurationLocal extends ResourceServerConfigurerAdapter{
private static final String LOCAL = "local";
@Value("${id.local.oauth}")
private String id;
@Value("${clientId.local.oauth}")
private Integer clientId;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.authenticationProvider(LocalAuthenticationProvider.getLocalAuthenticationProvider(id, clientId));
}
@Override
public void configure(final ResourceServerSecurityConfigurer resources) {
resources
.tokenExtractor(request -> new UsernamePasswordAuthenticationToken(LOCAL, LOCAL))
.tokenServices(ResourceServerTokenServicesLocal.getResourceServerTokenServices());
}
private static class LocalAuthenticationProvider {
private static AuthenticationProvider getLocalAuthenticationProvider(String id, Integer clientId) {
return new AuthenticationProvider() {
@Override
public Authentication authenticate(Authentication authentication) {
log.info("Logged with ID: {}", id);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(id, LOCAL);
token.setDetails(CustomUserDetails.builder().userId(clientId).build());
return new OAuth2Authentication(null, token);
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
};
}
}
private static class ResourceServerTokenServicesLocal {
private static ResourceServerTokenServices getResourceServerTokenServices() {
return new ResourceServerTokenServices() {
@Override
public OAuth2Authentication loadAuthentication(String accessToken) {
return new OAuth2Authentication(
Oauth2RequestLocal.getOauth2Request(),
new UsernamePasswordAuthenticationToken(LOCAL, LOCAL));
}
@Override
public OAuth2AccessToken readAccessToken(String accessToken) {
return new DefaultOAuth2AccessToken(LOCAL);
}
};
}
}
private static class Oauth2RequestLocal {
private static OAuth2Request getOauth2Request() {
return new OAuth2Request(Collections.emptyMap(),
"clientId1",
null,
true,
Collections.emptySet(),
null,
"http://local",
null,
null);
}
}
}
What I have tried so far:
@Configuration
@EnableWebSecurity
@Profile("local")
public class ResourceServerConfigurationLocal extends WebSecurityConfigurerAdapter {
private static final String LOCAL = "local";
@Value("${id.local.oauth}")
private String id;
@Value("${clientId.local.oauth}")
private Integer clientId;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.authenticationProvider(LocalAuthenticationProvider.getLocalAuthenticationProvider(id, clientId));
}
private static class LocalAuthenticationProvider {
private static AuthenticationProvider getLocalAuthenticationProvider(String id, Integer clientId) {
return new AuthenticationProvider() {
@Override
public Authentication authenticate(Authentication authentication) {
log.info("Logged with ID: {}", id);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(id, LOCAL);
token.setDetails(CustomUserDetails.builder().userId(clientId).build());
return new OAuth2AccessTokenAuthenticationToken(
RegisteredClient.withId(clientId.toString()).clientId(clientId.toString()).clientName(id).build(),
token,
new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"a",null,null));
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
};
}
}
}
Thanks in advance.