Integrar autenticación OAuth con Keycloak, Shiro, Apache Tapestry y Spring Boot
Escrito por
el , actualizado el .
java
planeta-codigo
programacion
Enlace permanente
Comentarios
OAuth es un protocolo usado para permitir a una aplicación acceder a los recursos de un usuario sin que este proporcione a la aplicación cliente sus credenciales y manteniendo el control de revocar los permisos concedidos. Es ampliamente usado por los servicios de redes sociales de las empresas más conocidas, también lo podemos usar en nuestras aplicaciones. En el ejemplo usaré Keycloak y una aplicación Java con Spring Boot, Apache Shiro y Apache Tapestry.
El protocolo OAuth permite a una aplicación cliente acceder a los recursos de un usuario almacenados en otra aplicación sin que el usuario proporcione a la aplicación cliente sus credenciales, además el usuario tiene la capacidad de revocar en caulquier momento los permisos concedidos a la aplicación cliente. El protocolo OAuth es ampliamente usado por empresas como Google, Facebook, Twitter en sus aplicaciones y servicios. También aplicando una arquitectura de microservicios, al dividir una aplicación en varios módulos o simplemente varias aplicaciones independientes pero que son usadas al mismo tiempo por el mismo usuario para evitar que el usuario se autentique en cada aplicación individualmente y que cada aplicación implemente la funcionalidad de autenticación podemos centralizarla usando OAuth a modo de autenticación única o SSO. Usando Keycloak como servidor de OAuth podemos integrarlo en una aplicación Java que use Apache Shiro para la autorización, Spring Boot para iniciar la aplicación y Apache Tapestry como framework web.
En el protocolo OAuth se diferencia las aplicaciones cliente que son capaces de mantener seguras sus credenciales como es el caso de una aplicación web ejecutada en el servidor o las aplicaciones que no son capaces de mantener sus credenciales seguras como es el caso de una aplicación cliente ejecutada en el navegador o en algunos casos nativa en el móvil. Independientemente de la aplicación cliente o de los varios flujos de autenticación el acceso a los recursos del usuario se hace mediante la obtención de un token que es una cadena de caracteres opaca de cierta longitud pero que descifrada contiene información del usuario autenticado también está firmada digitalmente por el servidor de OAuth para evitar alteraciones. El protocolo define varios flujos para obtener un token, obtenido el token con cualquiera de ellos el acceso a los recursos es indiferente del flujo que haya sido empleado.
En una aplicación segura con el grant de tipo authorization code los pasos que se siguen son los siguientes:
- El servidor redirige al usuario al servidor de OAuth cuando intenta acceder a una URL protegida.
- El usuario introduce sus credenciales en una página de inicio de sesión proporcionada por el servidor OAuth, normalmente un usuario y contraseña.
- El servidor OAuth envía al navegador una redirección hacia la aplicación proporcionado un código de autorización en la URL que puede intercambiarse por un token.
- El navegador con la redirección envía el código de autorización al servidor, el servidor obtiene de la URL, obtiene el código de autorización y lo usa para intercambiarlo por un token del servidor OAuth proporcionado además las credenciales del cliente.
- Obtenido el token con los permisos adecuados la aplicación ya puede permitir acceso o acceder a los recursos.
Para obtener el token el servidor mantiene seguras sus credenciales como cliente OAuth. Nótese también que con el token el servidor (cliente OAuth) no necesita comunicarse con el servidor OAuth para validar el token ya que está firmado digitalmente, cifrado y tiene concedido un periodo de validez.
Un cliente se considera inseguro si la aplicación cliente no puede mantener seguras sus credenciales, si las credenciales de la aplicación están en el navegador o en una aplicación nativa del móvil se considera que las credenciales podrían obtenerse. En una aplicación web en un servidor las credenciales de la aplicación se mantienen seguras en el servidor.
El siguiente ejemplo muestra como autenticar con Keycloak como proveedor de OAuth una aplicación Java que usa Shiro para la autorización, Spring Boot y el framework web Apache Tapestry. OAuth y Keycloak también puede usarse para securizar con OAuth un servicio REST con JAX-RS y crear un cliente Java para acceder al servicio REST securizado con OAuth empleando el flujo client credentials. Lo mostrado en este artículo solo es una pequeña parte de las opciones y posibilidades que ofrece Keycloak, en las capturas de pantalla mostradas hay muchas pestañas, opciones y campos con funcionalidades adicionales.
Iniciar el servidor OAuth de Keycloak usando Docker es muy sencillo con el siguiente comando y archivo de Docker Compose, en el primer acceso se nos solicitará una clave y contraseña de administración:
|
|
|
|
Para el ejemplo crearé un nuevo realm que contendrá los usuarios y en el que registraremos la aplicación cliente.
Usando uno de los adaptadores proporcionados por Keycloak para la integración en servidores y aplicaciones su uso no es complicado, en este caso usaré el adaptador para Spring Boot. Usándolo básicamente deberemos proporcionar en la configuración las credenciales de la aplicación cliente que hemos registrado previamente en Keycloak. Además indicaremos que URLs de la aplicación requiere autenticación y que roles han de poseer los usuarios autenticados. Al acceder a estas URLs el adaptador de Keycloak redirigirá al servidor para que el usuario se autentique, una vez autenticado se redirigirá a la aplicación de nuevo.
|
|
Autenticado el usuario podemos obtener la instancia de AccessToken que representa el token de OAuth, para la autorización podemos usar Apache Shiro y para ellos deberemos implementar un Realm de tipo AuthorizingRealm. Tiene dos métodos que deberemos implementar doGetAuthenticationInfo y doGetAuthorizationInfo, el primero lo usaremos para autenticar al usuario que en este caso teniendo el AccessToken ya estará autenticado con Keycloak y el segundo método nos permitirá obtener los roles y permisos asociados al usuario que podríamos obtenerlos de una base de datos relacional, en el ejemplo los roles también se obtienen del token. Con un filtro realizaremos el inicio de sesión de forma programática del usuario representado por el AccessToken cuando esté presente en la petición.
|
|
|
|
Con Apache Tapestry el filtro se registra en el módulo de la aplicación y con Shiro podemos realizar la autorización necesaria en las páginas u acciones de la aplicación usando anotaciones. En este caso una página pública que no requiere estar autenticado, una página accesible por un usuario autenticado y con rol user y finalmente una página de administración que requiere rol admin.
|
|
|
|
|
|
|
|
|
|
|
|
Como la página de inicio no requiere autenticación es accesible por cualquier usuario. Al navegar a la página de usuario o administrador se iniciará el proceso de autenticación primeramente redirigiéndonos al servidor Keycloak para que introduzcamos las credenciales.
Si intentamos acceder a la página de usuario o administrador sin estar autenticados se nos mostrará la página de error 403 y al acceder a la página de administración con un usuario sin rol admin se nos mostrará la página de error 401.
Un buen libro sobre OAuth que he leído es Mastering OAuth 2.0 que explica detalladamente el protocolo OAuth junto con el resto de formas de obtener un token además del mostrado en este artículo usando las credenciales del cliente.
Este artículo solo es introductorio a las posibilidades de OAuth y Keycloak, entre otras posibilidades que ofrece Keycloak creo que está permitir registrarse a los usuarios o personalizar los estilos y páginas de autenticación.
El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:./gradle run
Libro PlugIn Tapestry
Si te interesa Apache Tapestry descarga gratis el libro de más de 300 páginas que he escrito sobre este framework en el formato que prefieras, PlugIn Tapestry: Desarrollo de aplicaciones y páginas web con Apache Tapestry, y el código de ejemplo asociado. En el libro comento detalladamente muchos aspectos que son necesarios en una aplicación web como persistencia, pruebas unitarias y de integración, inicio rápido, seguridad, formularios, internacionalización (i18n) y localización (l10n), AJAX, ... y como abordarlos usando Apache Tapestry.