I want to develop two independent services, one for the business stuff and one for the user authentication using Spring OAuth 2
Let's call them Business-Service and OAuth-Service.
Now I want the Business-Service delegate to the OAuth-Service if a request is not authenticated. The client application (an Android app) should not know about the OAuth-Service a priori, it should only be delegated to it by the Business-Service with an 302 HTTP redirect for non-authenticated request. To be precise, I want my API landing page to provide a link to http://businessservice.com/login and when my client app decides to follow this link, it gets redirected to the OAuth-Service.
If I annotate the Business-Service with @EnableOAuth2Resource , all of its resources are protected returning a 401 when I curl them without an access token. So far so good. If I provide an access token like this:
curl -v http://localhost:8667/resource/ -H "Authorization: Bearer $TOKEN"
I can access the resource. Still good.
However if I annotate the Business-Service with @EnableOAuth2Sso for enabling the redirection to the OAuth service, it looses the capability of accessing the resources with an access token (same curl as above), it only returns a 302 to the login page http://localhost:8667/login
If I use both annotations, the @EnableOAuth2Resource always seems to "win", as the authentication works but calling http://localhost:8667/login returns a 404.
So what is the right way to create a resource server that delegates to the auth server for non-authenticated calls?
After trying around for hours I now found a solution.
The Business Server (Resource Server) now looks as follows:
@SpringBootApplication
@EnableOAuth2Sso
@EnableOAuth2Resource
public class BusinessService {
public static void main(final String[] args) {
final ConfigurableApplicationContext context = SpringApplication.run(BusinessService.class, args);
}
}
with two configurations, one for the SSO:
@Configuration
public class OAuth2SsoConfiguration extends OAuth2SsoConfigurerAdapter {
@Override
public void match(final RequestMatchers matchers) {
matchers.antMatchers("/");
}
@Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
}
}
and one for the Resource:
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(final HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/resource/**").and().authorizeRequests().anyRequest().authenticated().antMatchers("/").permitAll();
}
}
This results in the following:
curl -v http://localhost:8667/
returns
HTTP/1.1 200 OK
{"links":[{"rel":"login","href":"http://localhost:8667/login"}]}
curl -v http://localhost:8667/resource/
returns
HTTP/1.1 401 Unauthorized
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
curl -v http://localhost:8667/login
returns
HTTP/1.1 302 Found
Location: http://localhost:8666/user/oauth/authorize?client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A8667%2Flogin&response_type=code&state=YmmNO9
So my business servie is secured with as a resource server returning a 401 for all business resources. The root of the service is applicable for all clients so they can discover the login relation and if they follow this relation, they're redirected to the Authorization server
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With