Autenticación con token en servicios REST

En esta wiki vamos a explicar el mecanismo de autenticación con token para poder incorporarlo a nuestros servicios REST. El mecanismo funciona interceptando las peticiones que hacen a nuestra aplicación lanzando automáticamente la autenticación de manera transparente aceptando o rechazando la petición según proceda. Paralelamente este mecanismo gestiona la creación y actualización de los token de usuario por lo que libera a los programadores de dicha tarea.

Este mecanismo tiene unas precondiciones que nuestro proyecto debe cumplir:

El servicio de autenticación con token se basa en dos listener para las peticiones entrantes/salientes en los cuales se lleva a cabo la tarea de validación de usuario y/o token, aceptando o denegando la petición según proceda. De esta manera los desarrolladores no necesitan incluir validaciones explícitas en su código evitando olvidos a la hora de comprobar los accesos. Es importante cumplir las precondiciones indicadas en el apartado anterior para asegurar el buen funcionamiento del sistema.

Envío de cabeceras

Todas las peticiones que se hagan al servicio para la parte privada o el login deberán incluir la cabecera de autorización Authorization.

En dicha cabecera deberán incluirse:

  • Si queremos hacer login: usuario:contraseña, codificado en Base64
  • Si accedemos aun método private: usuario:token, condificado en Base64

Listener de peticiones

El listener de peticiones escucha todas las peticiones entrantes y las respectivas respuestas actuando para cada petición rest recibida. Cada vez que se accede a una ruta que esté en el path ../private/.. el listener obtendrá la cabecera de autenticación y realizará las comprobaciones oportunas según el caso para comprobar si el solicitante tiene acceso o no al método.

Cuando queramos hacer login, nuestra aplicación dispondrá por defecto de un método http://miproyecto.um.es/miproyecto/rest/vx.x/public/login en el cual el usuario podrá loguearse con su usuario y contreña. Este método no hay que crearlo en nuestro servicio REST ya que está incluido por defecto. El cliente mandará usuario:password codificado en Base64 en la cabecera de autenticación y el listener de peticiones tras detectar que se intenta acceder a la url de login lanzará la autenticación del usuario (que deberemos implementar). En caso existoso se creará un token para dicho usuario, borrando los existentes y se devolverá codificado en Base64.

Cuando queramos acceder a un servicio dentro del path ../private/.. deberemos mandar usuario:token, codificado en Base64. En este caso el servicio recuperará el token, comprobará que existe y no está caducado y, en caso afirmativo, actualizará el tiempo de vida del token y ejecutará la petición que el usuario había solicitado.

En caso de tener una autenticación diferente de usuaripo:password, podremos extender la clase encargada de autenticar para modificar ese comportamiento.

Estructura de clases

Las clases que vienen creadas por defecto en el módulo de autenticaciónn REST son las entidades, DAS y servicios necesarios para gestionar los usuarios y los token. A su vez, se incluye una clase que controla la autenticación, la cual puede ser sobrescrita si deseamos modificar la autenticación por defecto.

Ésta infraestructura es utilizada por dos filtros: RestRequestFilter y RestResponseFilter

RestRequestFilter: Filtro que analizará todas las peticiones a las rutas ../private/.. y comprobará si el usuario que solicita el servicio tiene un token válido para ejecutarlo.

RestResponseFilter: Filtro que analiza todas las peticiones a public/login y lanza la autenticación.

RestAuthenticationProvider: Clase encargada de gestionar la autenticación tanto por usuario:password, como usuario:token. Puede ser sobrescrita para cambiar la manera de autenticarse.

ServicioAutorizacionRest: Servicio encargado de cargar y persistir los datos relativo a la autenticación y generar o limpiar los token de usuario.

Creación de base de datos

La primera acción que debemos llevar a cabo es ampliar nuestro esquema de base de datos, para ello deberemos crear dos tablas para la gestión de usuarios y tokens de nuestra aplicación:

  • REST_USUARIOS: Guardará una relación de usuario/password habilitados para consultar los servicios REST de nuestra aplicación.
  • REST_USUARIO_TOKEN: Guardará una relación de los token creados en la aplicación y los usuarios a los que pertenecen.

Este esquema de tablas puede crearse a partir del script de creación. El tiempo de duración de sesión del token se establece como valor por defecto en la tabla REST_USUARIO_TOKEN en milisegundos (por defecto son 5 minutos).

En la tabla REST_USUARIOS los password se guardarán encriptados. El código fuente del servicio incorpora el algoritmo de encriptación a falta de especificar la clave de cifrado que debe ser configurada por aplicación. Para las pruebas, dentro del paquete “util” del código fuente se ha añadido una clase para encriptar un password dado.

Los fuentes para la autenticación rest los tienes en este empaquetado.

Configuración

Por último, una vez incorporado los fuentes a nuestro proyecto, sólo quedaría configurar los filtros para que se lancen en todas las peticiones sobre la url http://miaplicacion.um.es/miaplicacion/rest para ello debemos añadir en el fichero web.xml el siguiente código

En el nombre de los paquetes cambiar “miapliacion” por el nombre del proyecto

Donde debemos indicar dónde se encuentran las clases que harán de filtro. Para aplicaciones FundeWeb 2.0.

	<context-param>
	  <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
	  <param-value>es.um.atica.miaplicacion.security.rest.filter.RestRequestFilter</param-value>
	</context-param>
 
	<context-param>
	  <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
	  <param-value>es.um.atica.miaplicacion.security.rest.filter.RestResponseFilter</param-value>
	</context-param>



Este paso solo es necesario en aplicaciones FundeWeb 1.5 migradas a Weblogic 12.2. Tenemos que abrir el fichero cxf-beans.xml y añadimos los siguientes beans al final del fichero:

    ...
    <bean id="securityContainerRequestFilter" class="org.umu.atica.miaplicacion.security.rest.filter.RestRequestFilter"/>
    <bean id="securityContainerResponseFilter" class="org.umu.atica.miaplicacion.security.rest.filter.RestResponseFilter"/>

Para poder utilizarlos, tenemos que añadirlos a un elemento <jaxrs:server> o <jaxrs:client>.

    <jaxrs:server id="servicioRest" address="/rest">
        <jaxrs:serviceBeans>
            <ref bean="serviceBean" /> <!-- Un servicio Rest -->
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <ref bean="genericExceptionMapper"/>
            <ref bean="genericThrowableMapper"/>
            <ref bean="webApplicationExceptionMapper"/>
 
            <!-- Request Filters -->
            <ref bean="problemContainerRequestFilter"/>
            ...
            <ref bean="securityContainerRequestFilter"/>
 
            <!-- ResponseFilters -->            
            <ref bean="securityContainerResponseFilter"/>
            ...                        
            <ref bean="problemContainerResponseFilter"/>
 
            <ref bean="problemMessageBodyWriter"/>
        </jaxrs:providers>
    </jaxrs:server>

Hay que tener encuenta que problemContainerRequestFilter tiene que ser el primer ContainerRequestFilter declarado y que problemContainerResponseFilter tiene que ser el último ContainerResponseFilter declarado.

  • fdw2.0/fundeweb2.0/gt/rest/autenticacion_de_servicios_web_rest_token.txt
  • Última modificación: 13/05/2021 11:21
  • por PEDRO DELGADO YARZA