Gestión de APIs

WSO2 API IS Tutorial: Cómo usar JWT Tokens para intercambiar datos

4th abril 2019

JWT Tokens es un estándar abierto para la compartición de datos en un formato de objeto JSON. Este objeto contendrá información y privilegios del usuario, también conocidos como claims. El estándar establece mecanismos que nos permiten asegurar y autenticar los datos enviados.

Qué debes saber sobre JWT Token  

El token JWT se encuentra diferenciado en tres partes:

  • Cabecera o header: Donde se indica el algoritmo con el cual se ha codificado el token.
{"typ": "JWT", "alg": "none"}
  • Contenido o payload: Donde se incluye los claims asociados al usuario representados como una pareja clave/valor cada uno.
{
  "http://wso2.org/claims/role": [
    "admin"
  ],
  ...
  "http://wso2.org/claims/subscriber": "userJwt",
  "http://wso2.org/claims/tier": "Unlimited",
  "http://wso2.org/claims/applicationid": "6",
  "http://wso2.org/claims/usertype": "APPLICATION",
  "http://wso2.org/claims/apicontext": "/contextName/v1"
}
  • Firma o signature: Donde se codifica el contenido concatenado de las anteriores secciones con HMAC-256. Generando un hash que nos permita validar la autenticidad del contenido y por tanto la confianza del mismo.

-Este post te interesa: WSO2 MSF4J Tutorial «Conexión con el IS y OAuth 2.0»-

Funciones de JWT Token

JWT presenta dos funcionalidades principales, las cuales nos indicarán cuándo debemos utilizarlo:

  • Autorización: Los tokens JWT pueden ser utilizados como access token entre aplicaciones, incluyendo los privilegios del usuario. Estos serán incluidos en cada llamada, una vez el usuario se encuentre autenticado. . Esta suele ser la opción más usada.
  • Intercambio de datos: A través de los claims incluidos en su payload.

JWT Token ejemplo práctico

En nuestro ejemplo, haremos uso de tokens de acceso OAuth2 para la autorización de llamadas a la API y JWT para la transferencia de datos de usuario entre ésta y el backend.

De esta forma podremos intercambiar información de carácter confidencial entre el API Manager y el backend (usualmente un Enterprise Integrator), de una forma automatizada y segura.

Y para ello, utilizaremos un API Manager y un Identity Server como núcleo central del mismo, donde además configuraremos al Identity Server como Key Manager, de ahora en adelante IS-KM. Así tendremos centralizada en el IS-KM la gestión de usuarios y las tareas de autorización.

Así, lograremos definir un  un ejemplo práctico en el cual realicemos una llamada genérica a la API pasando únicamente como identificador el access token de usuario. Una vez allí será donde  el IS-KM validará el token y proveerá al backend de las claims del usuario, permitiendo así realizar una respuesta personalizada para el usuario.

1. Comunicación entre API Manager e Identity Server

API Manager & Identity Server

La comunicación se realizará de la siguiente forma:

1.Obtención de token de usuario:

a. El usuario se suscribirá a una API  existente a través del API Store.

b. El API Store delegará el control al API Gateway, el cual se conectará con el IS-KM y obtendrá un access token.

2. Llamada al sistema con el token de usuario:

a. El usuario llamará a un recurso concreto de la API con este access token obtenido.

b. El API Gateway comprobará la existencia de dicho access token y redirigirá la llamada al IS-KM para su validación. Esta llamada se realizará a través de servicios web, tal y como veremos más adelante.

c. El IS-KM validará el access token y pasará al API Gateway el control y los claims asociados al usuario que realizó la llamada en el formato de JWT.

d. El API Gateway redirigirá la llamada al backend asociado a la API, añadiendo una cabecera de tipo ‘X-JWT-Assertion’ con el JWT codificado en Base64.

-No te pierdas: WSO2 MSF4J Tutorial «Funcionalidades avanzadas para crear microservices»-

2. Intercambio de datos entre API Manager e Identity Server

data exchange API Manager & Identity Server

El primer paso es identificar y crear los distintos esquemas que necesitamos en este caso. Los esquemas que deben ser compartidos por ambos productos, son los siguientes:

  • WSO2REG_DB: este esquema  almacenará la información del registry, para compartir configuraciones internas entre productos de WSO2. En nuestro caso mantendremos la H2 por defecto, aunque debería utilizarse una para ambos productos.  
  • WSO2UM_DB: aquí se aglutinará la información relativa a los permisos y los roles de usuario.  
  • WSO2US_DB: este esquema reservará la información relacionada   con los usuarios.
  • WSO2AM_DB: esquema que reúne la información relativa a OAuth tokens, suscripciones, etc.

Respecto a los  scripts para BBDD, estos vienen incluidos dentro de la carpeta ‘dbscripts’ en cada uno de los productos de WSO2. En  nuestro ejemplo utilizaremos un esquema único para WSO2UM_DB y WSO2US_DB, denominado: WSO2UM_DB.

-Quizá te interese: WSO2 MSF4J Tutorial «WebSockets»-

En ambos productos deberemos realizar los siguientes cambios:

1. Modificar el fichero ‘/repository/conf/datasources/master-datasources.xml’, para crear un datasource con cada una de nuestras conexiones a BBDD y tener así un mejor desempeño.

<datasource>
 <name>WSO2UM_DB</name>
 <description>The datasource used for registry and user  mngr</description>
 <jndiConfig>
   <name>jdbc/WSO2UM_DB</name>
 </jndiConfig>
 <definition type="RDBMS">
  <configuration>
   <url>jdbc:mysql://localhost:3306/JWT_UM_DB</url>
   <username>root</username>
   <password>CHANGE_ME</password>
   <driverClassName>com.mysql.jdbc.Driver</driverClassName>
   <maxActive>50</maxActive>
   <maxWait>60000</maxWait>
   <testOnBorrow>true</testOnBorrow>
   <validationQuery>SELECT 1</validationQuery>
   <validationInterval>30000</validationInterval>
   <defaultAutoCommit>false</defaultAutoCommit>
  </configuration>
 </definition>
</datasource>
<datasource>
 <name>WSO2AM_DB</name>
 <description>The datasource for token and API information</description>
 <jndiConfig>
  <name>jdbc/WSO2AM_DB</name>
 </jndiConfig>
 <definition type="RDBMS">
  ...
 </definition>
</datasource>

2. Incluir la librería con los drivers de la BBDD en caso de que no estemos usando la H2 que viene configurada por defecto y que no es recomendable para entornos productivos. El archivo se debe incluir en la ruta ‘/repository/components/lib/’.

3.Cambiamos el fichero ‘/repository/conf/user-mgnt.xml’, indicando lo siguiente:

a.Indicamos en la propiedad ‘/UserManager/Realm/Configuration/Property/@dataSource’ el datasource que contendrá la configuración de usuarios básica del sistema.

<Configuration>
 <AddAdmin>true</AddAdmin>
 <AdminRole>admin</AdminRole>
 <AdminUser>
  <UserName>admin</UserName>
  <Password>CHANGE_ME</Password>
 </AdminUser>
 <EveryOneRoleName>everyone</EveryOneRoleName>
 <Property name="isCascadeDeleteEnabled">true</Property>
 <Property name="initializeNewClaimManager">true</Property>
 <Property name="dataSource">jdbc/WSO2UM_DB</Property>
</Configuration>


b. 
Borrar la configuración por defecto que utiliza como user store principal, donde se guardarán los usuarios y sus datos, LDAP.

c. Configurar el user store principal con nuestra BBDD. En este caso no nos servirá indicar únicamente el nombre del datasource configurado.

<UserStoreManager class="org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager">
 <Property name="TenantManager">org.wso2.carbon.user.core.tenant.JDBCTenantManager</Property>
 <Property name="url">jdbc:mysql://localhost:3306/JWT_UM_DB</Property>
 <Property name="userName">root</Property>
 <Property encrypted="false" name="password">CHANGE_ME</Property>
 <Property name="driverName">com.mysql.jdbc.Driver</Property>
 ...
</UserStoreManager>

4. Modificar el fichero ‘/repository/conf/identity/embedded-ldap.xml’ para deshabilitar el LDAP configurado por defecto. Tendremos que poner ‘false’ en el valor de la propiedad ‘/EmbeddedLDAPConfig/EmbeddedLDAP/Property/@enable’.

5. Modificar el fichero ‘/repository/conf/identity/identity.xml’ y configurar la BBDD que contendrá la información sobre tokens y/o suscripciones.

<Server xmlns="http://wso2.org/projects/carbon/carbon.xml">
 <JDBCPersistenceManager>
  <DataSource>
   <Name>jdbc/WSO2AM_DB</Name>
  </DataSource>
  ....
 </JDBCPersistenceManager>
</Server>

3. Configuración de API Manager e Identity Server para el uso de JWT

El siguiente paso será configurar ambos productos para que se comuniquen correctamente entre sí y  permitan, por un lado obtener los access token del IS-KM, y por otro lado, el paso de claims desde el API al backend.

En ambos productos debemos configurar:

1. Cambiar el fichero ‘/repository/conf/api-manager.xml’ y descomentar las variables que indicamos a continuación, así habilitaremos el uso de JWT en el producto.

a. ClaimsRetrieverImplClass. Clase que nos permite obtener las user claims

b. ConsumerDialectURI. Dialecto asociado a las claims.

c. SignatureAlgorithm. Algoritmo de seguridad con el que encriptar las claims. Indicaremos ‘NONE’ para el ejemplo, para más seguridad indicar ‘SHA256withRSA’.

Así será la configuración para el IS-KM:

2. Cambiar el fichero ‘/repository/conf/carbon.xml’ para indicar otro offset en el caso de que tengamos ambos productos desplegados en la misma máquina.

La configuración para el API Manager deberá ser:

3. Cambiar el fichero ‘/repository/conf/api-manager.xml’

a. Para indicar el gestor de autenticaciones a través de las propiedades ‘AuthManager’. Tal como comentamos antes, esta gestión se realizará a través de los web services de administración del propio IS-KM y esa será la URL que debemos indicar. ¡Atento al cambio de offset en el IS-KM!:

<AuthManager>
 <ServerURL>https://localhost:9444${carbon.context}services/</ServerURL>
 <Username>CHANGE_ME</Username>
 <Password>CHANGE_ME</Password>
 <CheckPermissionsRemotely>false</CheckPermissionsRemotely>
</AuthManager>

b. Modificar la propiedad ‘APIKeyValidator’ con los datos anteriores e indicando que la validación se realizará a través de servicio web y no con el servidor Thrift

<APIKeyValidator>
 <ServerURL>https://localhost:9444${carbon.context}services/</ServerURL>
 <Username>CHANGE_ME</Username>
 <Password>CHANGE_ME</Password>
 <KeyValidatorClientType>WSClient</KeyValidatorClientType>
 <ThriftClientConnectionTimeOut>10000</ThriftClientConnectionTimeOut>
 <EnableThriftServer>false</EnableThriftServer>
 <ThriftServerHost>localhost</ThriftServerHost>
<KeyValidationHandlerClassName>org.wso2.carbon.apimgt.keymgt.handlers.DefaultKeyValidationHandler</KeyValidationHandlerClassName>
</APIKeyValidator>

4. Ejemplo entre API Manager e Identity Server

Tras todo lo comentado anteriormente, ya tendríamos correctamente configurados ambos productos y solo deberíamos arrancarlos para comenzar la prueba.

Los pasos a realizar para obtener los resultados del ejemplo podrían ser los siguientes:

  1. Crear una API a través del API Publisher
  2. Asociar a dicha API un Enterprise Integrator (EI) en el backend o algún mock que nos permita ver las cabeceras en la llamada a dicho backend.
  3. Crear un usuario y darle permisos para subscribirse a APIs a través de la consola de administración (nos vale la del IS o la del APIM ya que tenemos la misma BBDD).
  4. Logarse en el API Store con el usuario creado, crear una aplicación y subscribirse a la API de pruebas creada en el punto 1.
  5. Obtener el token para la aplicación del usuario creado.
  6. Llamar a la API con el token de acceso.

Si estamos ‘logando’ correctamente en el backend o utilizando un mock para el mismo, podremos ver la información de las cabeceras en la llamada al mismo. La información que obtendremos será similar a esta:

wso2 api jwt token
Aunque el token JWT decidimos no cifrarlo, tendrá al menos una codificación en Base64. No obstante, si queremos ver correctamente su contenido podemos usar webs del tipo: https://jwt.io/.

Tras este tutorial seguro que ya estás un poco más preparado para explotar más funcionalidades de WSO2 Identity Server y API Manager.

¡Nos leemos en el siguiente post!

Daniel Blanco Chakray

 

 

 

 

 

 

open source apis guía chakray wso2