Ir al contenido principal

WSO2 MSF4J Tutorial: Conexión con el IS y OAuth 2.0

En el anterior post pudimos ver cómo realizar una autenticación básica. En el artículo de hoy veremos cómo realizar esa misma autenticación pero a través del Identity Server (IS) de WSO2 y OAuth 2.0.

Para ello empezaremos indicando los cambios que debemos hacer en el IS y después procederemos a detallar  los que debemos realizar en nuestro servicio.

-Antes de continuar: Actualiza tus conocimientos sobre WSO2 Identity Server-  

Creación del SP en el Identity Server

Para comenzar debemos tener acceso a un Identity Server y a su consola de administración. Ahí es desde donde deberemos crear un ‘service provider’ de tipo ‘Inbound authenticators’ para una autenticación de tipo OAuth 2.0.

Como única configuración diferente de la de por defecto, debemos indicar la propiedad ‘Callback Url’, en la cual indicaremos ‘https://localhost:9443/oauth2/token’. Una vez registrado el ‘service provider’, éste nos proveerá del client key y secret.

Obtención del access token de aplicación a través del Identity Server

A través de estos datos y de la callback URL podremos realizar la primera de las tres fases de la autenticación en 3 pasos de OAuth 2.0. Permitiéndonos, así, obtener un access token a través del comando:

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

Ese token que viajará en cada una de las llamadas a nuestro microservicio deberá ser validado y para ello utilizaremos otra URL del IS: ‘https://localhost:9443/oauth2/introspect’. La cual nos nos informará  si es válido o no. Más adelante veremos como su utilización dentro del microservicio.

Configuración del filtro de cabecera de autenticación en el servicio

Ahora es el momento de ver  los cambios a realizar en nuestro microservicio para lograr la autenticación deseada.

Para empezar debemos decidir cuál será el ámbito en el que realizaremos la autenticación, pudiendo elegir un enfoque global o por servicios. En ambos casos utilizaremos el interceptor proporcionado por WSO2, ‘OAuth2SecurityInterceptor’.

La diferencia es que si elegimos un enfoque global deberemos configurarlo en la clase ‘núcleo’ de nuestra aplicación, como un ‘GlobalRequestInterceptor. Mientras que si  lo hacemos a nivel de servicio lo podremos configurar en el mismo servicio, a través de la anotación ‘@RequestInterceptor’.

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

Este interceptor controlará si la petición tiene la cabecera ‘Authorization’ correspondiente. Si ésta contiene el formato correcto, y tras la verificación de tratar la respuesta y dejar paso o no al servicio consultado. Pero no se encargará de la verificación propiamente, para ello necesita de una URL que realice dicha verificación y le dé una respuesta positiva o negativa.

Por tanto,  por un lado debemos configurar esa URL para la verificación y por otro lado, crear un servicio de autenticación que responda a esa URL y le dé una respuesta al ‘OAuth2SecurityInterceptor’.

-Leer más: Cómo crear microservicios con el módulo MSF4J de WSO2-

Configuración del servicio de autenticación de tokens

En nuestro servicio de autenticación delegaremos a su vez la autenticación en el propio Identity Server, a través del servicio anteriormente comentado en el paso 2, ‘introspect’. Por lo que solamente deberemos hacer una llamada HTTP a dicho servicio, pero logándonos con un usuario/contraseña que tenga permisos.

@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());
 }

Ahora  solo nos quedaría configurar la URL del servicio utilizado por el interceptor. Esto lo haremos en la clase en la que reside la configuración, y también añadiremos el nuevo servicio para que al llamarlo no proporcione un ‘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()]);
 }

Demostración

Una vez esté todo configurado y ya arrancada la aplicación, debes saber que ya no nos valdrá la anterior petición HTTP para obtener los datos. Sino que para conseguir una respuesta positiva deberemos añadir un access token válido, por ejemplo así:

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

Ahora es el momento de que tomes estos consejos prácticos y logres conectar tu Identity Server con OAuth 2.0. Si tienes dudas a la hora de implementarlo, consúltanos, en Chakray siempre estamos preparados para echarte una mano.

¡Hasta el próximo post tutorial de WSO2 MSF4J!

implementa WSO2 paso a paso Chakray