WSO2 MSF4J: IS y OAuth 2.0

WSO2 MSF4J Tutorial: Connection to IS and OAuth 2.0

28th March 2019

In the previous post, we explored how to perform basic authentication. In today’s article we will see how to perform that same authentication but through the Identity Server (IS) of WSO2 and OAuth 2.0.

To do this, we will start by explaining the changes we must make in the IS and then we will proceed to detail the changes we must make in our service.

-Before you continue: Update your knowledge about WSO2 Identity Server-

Creation of the SP in the Identity Server

To begin with, we must have access to an Identity Server and its administration console. That’s where we should create an ‘Inbound authenticators’ type ‘service provider’ for OAuth 2.0 type authentication.

As the only configuration different from the default one, we must indicate the property ‘Callback Url’, in which we will indicate ‘https://localhost:9443/oauth2/token’. Once the ‘service provider’ is registered, it will provide us with the client key and secret.

Obtaining the application access token through the Identity Server

Through this data and the URL callback, we will be able to perform the first of the three phases of authentication in 3 steps of OAuth 2.0. This allows us to obtain an access token through the command:

curl -v -k -X POST --basic -u <OAuth Client Key>:<OAuth Client Secret> -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" -d "grant_type=client_credentials" https://localhost:9443/oauth2/token

The token that will travel in each of the calls to our microservice must be validated and for this, we will use another URL of the IS: ‘https://localhost:9443/oauth2/introspect’. This will inform us if it is valid or not. Later we will see how to use it within the microservice.

Configuring the Authentication Header Filter in the Service

Now is the time to see the changes to be made to our microservice to achieve the desired authentication.

To begin with, we have to decide what the scope of authentication will be, and we can choose a global approach or by services. In both cases, we will use the interceptor provided by WSO2, ‘OAuth2SecurityInterceptor’.

The difference is that if we choose a global approach we must configure it in the ‘core’ class of our application, as a ‘GlobalRequestInterceptor. If we do it at service level we can configure it in the same service, through the annotation ‘@RequestInterceptor’.

@Path("/book")
@Produces(MediaType.APPLICATION_JSON)
@RequestInterceptor(OAuth2SecurityInterceptor.class)
public class BookServiceImpl implements BookService {

This interceptor will control if the request has the corresponding ‘Authorization’ header, if it contains the correct format and, after the verification of processing the response and giving way or not to the consulting service. But it will not be in charge of the verification itself, for that it needs a URL that carries out this verification and gives a positive or negative answer.

Therefore, on the one hand, we must configure that URL for verification and on the other hand, create an authentication service that responds to that URL and gives an answer to the ‘OAuth2SecurityInterceptor’.

-Read more: How to create microservices with the WSO2 MSF4J module-

Configuring the Token Authentication Service

In our authentication service, we will delegate the authentication to the Identity Server itself, through the service previously mentioned in step 2, ‘introspect’. So we only need to make an HTTP call to that service, but logging in with a user/password that has permissions.

@Path("/oauth2")
public class OAuthValidatorServiceImpl implements OAuthValidatorService {
private static final String TOKEN = "token";
private static final String ADMIN = "admin";
private static final String OAUTH2_INTROSPECT = "https://localhost:9443/oauth2/introspect";
@POST
@Path("/validate")
@Override
public String validate(@Context final Request request, @FormParam(value = "token") final String token)
         throws Exception {
     return callIntrospectWithToken(token);
}
private String callIntrospectWithToken(final String token) throws Exception {
     SSLContextBuilder builder = new SSLContextBuilder();
     builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
     SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
     HttpClient client = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build();
     HttpPost httppost = new HttpPost(OAUTH2_INTROSPECT);
     UsernamePasswordCredentials creds = new UsernamePasswordCredentials(ADMIN, ADMIN);
     httppost.addHeader(new BasicScheme().authenticate(creds, httppost, null));
     List<NameValuePair> params = new ArrayList<>(2);
     params.add(new BasicNameValuePair(TOKEN, token));
     httppost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8.name()));
     HttpResponse response = client.execute(httppost);
     return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8.name());
}
}

Now we only need to configure the URL of the service used by the interceptor. We will do this in the class in which the configuration resides, and we will also add the new service so that calling it does not provide a ‘Not Found Error’.

public static void main(final String[] args) {
     System.setProperty("AUTH_SERVER_URL", "http://localhost:9090/oauth2/validate");
     EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.chakray.example.jpa.config");
     MetricsInterceptor mInterceptor = new MetricsInterceptor();
     new MicroservicesRunner().addInterceptor(mInterceptor).addExceptionMapper(new ServiceExceptionMapper())
             .deploy(getDeployService(emf)).start();
}
private static Object[] getDeployService(final EntityManagerFactory emf) {
     List<Object> services = new ArrayList<>();
     services.add(new BookServiceImpl(new BookDaoImpl(emf)));
     services.add(new OAuthValidatorServiceImpl());
     return services.toArray(new Object[services.size()]);
}

Demonstration

Once everything is configured and the application is started, you should know that the previous HTTP request to obtain the data is no longer valid. But to get a positive response we must add a valid access token, for example like this:

curl -v -H "Authorization: Bearer <OAuth Access token>"
http://localhost:9090/book/list

Now is the time for you to take these practical tips and connect your Identity Server to OAuth 2.0. If you have doubts when implementing it, ask us, in Chakray we are always ready to give you a hand.

See you on the next WSO2 MSF4J post-tutorial!

Steps to implement WSO2 in your company

Discover all you need to know to integrate your business' systems with WSO2 with our guide. Includes Case Studies!

Written By

Daniel Santiago Blanco Caudrado

Senior Integration Engineer en Chakray Consulting