Índice de contenidos.
1. Introducción
Keycloak es la solución open source de autenticación y autorización centralizada de RedHat. Agnóstica de cualquier tecnología, las principales características que ofrece son:
- Single-Sign On y Single-Sign Out para aplicaciones web y Apps.
- Soporte OpenID Connect, OAuth 2.0 y SAML.
- Identity Brokering – Autenticación por medio de un conector OpenID externo o por SAML Identity Providers.
- Social Login – Habilitar la gestión de login Google, GitHub, Facebook, Twitter y otras soluciones de redes sociales.
- User Federation – Sincronización de usuarios desde LDAP y Active Directory servers o RDBMS.
- Kerberos bridge – Autenticar automáticamente a los usuarios que han iniciado sesión en un servidor Kerberos.
- Consola de administración para la gestión centralizada de usuarios, roles, el mapeo de roles / usuarios, clientes (aplicaciones) y configuración.
- Consola de administración de cuentas que permite a los usuarios gestionar de forma centralizada su cuenta.
- Theme support – Personalizar todas las páginas de los distintos workflows (login, account, admin, email y welcome).
- Two-factor Authentication – Soporte para TOTP/HOTP via Google Authenticator o FreeOTP.
- Login flows – flujo de login configurable en un solo click opcional auto-registro de usuario, recuperación de contraseña, verificación de correo, actualización de password obligatorio, etc.
- Session management – Los administradores y los propios usuarios pueden ver y gestionar las sesiones de usuario.
- Token mappers – Mapeo de los atributos de usuarios, roles, etc., como uno lo desea en el token. Permite enriquecer el token.
- Políticas de revocación para realm, aplicaciones y usuario.
- Soporte CORS – Client adapters que han incorporado el soporte para CORS.
- Service Provider Interfaces (SPI) – un framework SPI que permite la personalización de los diversos aspectos del servidor. Flujos de autenticación, user federation providers, protocol mappers y mucho más.
- Client adapters para aplicaciones JavaScript, servidores WildFly, JBoss EAP, Fuse, Tomcat, Jetty, Spring, etc.
En este tutorial veremos cómo integrar keycloak con un front-end AngularJS y un back-end Spring Boot.
2. Entorno.
El tutorial ha sido escrito usando el siguiente entorno:
- Maven (Version 3.3.9)
- Spring Boot (Version 1.4.0.RELEASE)
- Keycloak (Version 2.1.0.Final)
- AngularJS (Version 1.5.0)
3. Creación de la política de autenticación y autorización en keycloak.
Una vez descargado e instalado el servidor keycloak, arrancamos el servidor ejecutando el script standalone.sh presente en la carpeta bin.
Una vez arrancado …
Abrimos el navegador e ingresamos en la consola de administración http://localhost:8080
Si es la primera vez, hay que crear previamente un usuario administrador (por ejemplo admin/admin)
Después de crear el usuario administrador, ingresamos en la consola de administración con este usuario pinchando en el enlace Administration Console. Por defecto keycloak utiliza un realm llamado master para gestionar sus propios usuarios. Por evitar cualquier interacción con este realm, es mejor crear uno propio.
Pasando el ratón sobre el realm Master, aparece un menu contextual con la opción Add realm.
Pinchando sobre la opción, aparecerá a la derecha un formulario donde indicaremos el nombre del nuevo realm que queremos crear.
A continuación, la consola de administración, una vez el realm creado, nos redirecciona sobre la página de configuración de este ultimo.
Seleccionamos el TabPanel Login y activamos las opciones de login User Registration y Forgot Password. En 3 clicks hemos añadido al flujo de login los típicos casos de uso de Alta de usuario y Olvido de contraseña.
4. Creación de roles en keycloak.
Ahora, vamos a añadir algunos roles aplicativo que se asignarán a usuarios mas adelante. Creamos dos roles, uno como super manager y otro como manager.
Seleccionamos la opción Roles en el panel de configuración, pulsamos en el botón Add Role en la parte derecha de la pantalla. Esto nos llevará hasta la pantalla Add Role. Introduzcamos super manager como nombre del primer rol y Guardamos. Creamos un segundo rol de nombre manager, aplicando la misma operativa
5. Creación de clientes en keycloak.
La noción de cliente en keycloak corresponde a una unidad de negocio de tipo front-end, back-end, microservicio o no.
Para este tutorial necesitamos crear dos clientes. Uno para el front-end de nuestra aplicación y otro para el back-end.
Seleccionamos la opción Clients en el panel de configuración, pulsamos en el botón Create en la parte derecha de la pantalla. Esto nos llevará hasta la pantalla Add Client.
Introduzcamos como client id account-front-end y guardamos.
La consola de administración nos redirecciona automáticamente al TabPanel Settings de la opción Clients. En la configuración, verificamos que la opción public del combobox Access Type está selecccionada.
Rellenamos los campos Valid Redirect URIs, Base URL y Web Origins con los siguientes valores
Valid Redirect URIs: http://localhost:8000/*
Base URL: http://localhost:8000/index.html
Web Origins: http://localhost:8000
Como es lógico de entender, esto indica que nuestra aplicación front-end debe ejecutarse en esta dirección
Ahora el cliente front-end está completamente configurado y se puede utilizar.
Vamos ahora crear otro cliente para el back-end de nuestra aplicación de nombre account-backend. Esta vez en la configuración seleccionamos la opción bearer-only en el combobox Access Type porque el back-end REST sólo debe ser invocado cuando un usuario ya está autenticado, por supuesto sin olvidarnos de guardar los cambios.
Ahora podemos dar por finalizado la configuración en el servidor Keycloak y atacar la integración de los adaptadores keycloak en nuestra aplicación.
6. Integración en el front-end AngularJS.
Keycloak proporciona un adaptador javascript que permite la comunicación entre el front-end y el servidor keycloak. Este adaptador permite, entre otras cosas, comprobar si el usuario está autenticado.
Lo primero, declaramos en la cabecera de nuestro fichero index.html (head) el fichero keycloak.js
<!DOCTYPE html>
<html lang="en">
<head>
<title>Account Demo
<meta name="viewport" content="initial-scale=1.0, user-scalable=yes">
<script src="//localhost:8080/auth/js/keycloak.js">
<script src="js/lib/angular-1.5.0.min.js">
<script src="js/lib/angular-route-1.5.0.min.js">
<script src="js/main.js">
<script src="js/main-controller.js">
</head>
<body>
<div ng-view>
</body>
</html>
En segundo lugar, tenemos que proporcionar al adaptador keycloak la configuración del servidor de identidad en un fichero con formato JSON.
Para obtener el archivo JSON, abrimos la consola de administración de keycloak y vayamos a la página del cliente account-frontend. A continuación, abrimos la pestaña Installation y elegimos la opción de formato Keycloak OIDC JSON.
Descargamos el archivo JSON y lo guardamos en la ruta /keycloak/keycloak.json por debajo de la webapp.
En el tratamiento del front, cargamos la configuración del servidor de identidad en un objeto _keycloak.
Para asegurarse que damos paso únicamente a un usuario autenticado, vamos a arrancar la aplicación angularjs manualmente una vez autenticado. En caso contrario se producirá un redirect a la página de login del servidor keycloak.
// on every request, authenticate user first
angular.element(document).ready(() => {
window._keycloak = Keycloak('keycloak/keycloak.json');
window._keycloak.init({
onLoad: 'login-required'
})
.success((authenticated) => {
if(authenticated) {
window._keycloak.loadUserProfile().success(function(profile){
angular.bootstrap(document, ['account-demo']); // manually bootstrap Angular
});
}
else {
window.location.reload();
}
})
.error(function () {
window.location.reload();
});
});
Para recuperar la información relativa al usuario autenticado podemos utilizar la función javascript loadUserProfile proporcionada por el adaptador. Eso es básicamente todo lo que se necesita para securizar un front-end angularjs.
Para asegurarnos que transmitimos la información relativa al usuario autenticado al back-end vamos añadir en la cabecera http del httpProvider el token generado por el servidor, siempre cuando este último no expire.
// use bearer token when calling backend
app.config(['$httpProvider', function($httpProvider) {
var isExpired = window._keycloak.isTokenExpired();
var token = window._keycloak.token;
if (sExpired) {
window._keycloak.updateToken(5)
.success(function() {
$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
})
.error(function() {
console.error('Failed to refresh token');
});
}
$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
}]);
7. Integración en el back-end Spring Boot.
Al igual que en el front-end, el back-end debe protegerse contra acceso no autorizado. Por lo tanto, sólo los usuarios autenticados deben ser aceptados.
En primer lugar, debemos declarar en el pom.xml del proyecto las dependencias keycloak de Tomcat y de Spring Boot.
<dependency>
<groupId>org.keycloak
<artifactId>keycloak-tomcat8-adapter
<version>${keycloak.version}
</dependency>
<dependency>
<groupId>org.keycloak
<artifactId>keycloak-spring-boot-adapter
<version>${keycloak.version}
</dependency>
Al igual que en el front-end, debemos proporcionar la configuración del servidor de identidad al back-end para poder comunicarnos con él.
Declaramos esta configuración en el fichero application.properties de Spring Boot. Estas son las propiedades de keycloak.
keycloak.realm = autentia
keycloak.realmKey = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiwBRXJWQu0XYIRoCen+2vmEMtkAXBs1nnIQQHJ0/IxxnVP9LwJUOX2/PYBBAaQlF2NEpTh2jMXAdPOwBDF8Vrc+25cbWIW47keUlNPmvZIMWJORIbcYmMZBBJrolSe3P5M3K8Lu75MLf1Fo6OQ6I+h0QSaifj8EQUBOYhXFL9enlC89HIHtAdddmVLPtMy2yoDFgzU8KKgo3bH0lbay8iwOrk+EHlorZHivfMjC8z1fhQq4d3aV9KXyhWQPs//SZLb+f4KcKVzdu43zA4r3UICml/JAPhP9LWIQXJXJ/Y6i90Ye4hUhXrQEe0N2I/C8w6Z9TOeYA6pp1WEktsnT7WwIDAQAB
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = account-backend
keycloak.bearer-only = true
keycloak.credentials.secret = 9801d0f9-710e-41ca-aba1-d83e20892b55
Los valores se pueden recuperar desde la consola de administración en la pestaña Installation del cliente account-backend.
Lo más importante, no olvidar el valor de la propiedad credentials.secret del cliente back-end, pestaña Credentials.
Para proteger nuestra API REST, podemos declarar las siguientes propiedades en el fichero de configuración application.properties.
keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = super manager
keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = manager
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*
Con esta declaración, estamos delegando en el servidor keycloak la política de autorización de nuestra API REST. Al igual que en Spring Security, estamos obligando a que el usuario autenticado tenga además uno de los dos roles especificados en la configuración.
Si la configuración es correcta el adaptador Spring Boot se encargará de interceptar las peticiones entrantes y rechazará las solicitudes no autorizadas.
Para poder recuperar la información relativa al usuario conectado en el back-end, el adaptador Spring Boot ofrece un objeto KeycloakPrincipal que se puede recuperar del contexto de seguridad. Implementamos un MethodArgument Resolver de Spring que se encargará de crear un objeto UserDetails a partir del objeto KeycloakPrincipal y lo inyectamos por medio de una anotación personalizada en cualquier método de un Controlador REST que lo necesite.
Para más información, os invito a consultar el código proporcionado en la siguiente dirección.
8. Demo.
Para arrancar la demo, lo primero nos bajamos los fuentes de la aplicación del repositorio Github.
A continuación, podemos configurar la aplicación de front-end y back-end con la configuración correcta de Keycloak como se ha descrito anteriormente o utilizamos la configuración existente proporcionada en el fichero keycloak/autentia-realm.json del proyecto, importándolo en el servidor Keycloak.
A continuación, abrimos una consola y nos posicionamos en la raíz del proyecto. Arrancamos la aplicación con el siguiente comando de maven.
Abrimos el navegador y vamos a la dirección http://localhost:8000.
La aplicación nos mandará a la página de login del servidor keycloak.
Nos registramos como nuevo usuario. Al finalizar el proceso, el servidor keycloak nos mandará de vuelta a la aplicación donde veremos algunos detalles acerca del usuario.
De momento el usuario no tiene ningún rol aplicativo asociado y como consecuencia no tiene los permisos adecuados para poder ejecutar cualquier lógica de negocio presente en el back-end.
Para ello, abrimos la consola de administración del servidor Keycloak y vayamos a la opción Users. A continuación, pulsamos en el botón View all users y seleccionamos el usuario autenticado. Después ir a la pestaña Role Mappings, asignamos el rol de super manager al usuario.
Volvemos a refrescar el navegador donde se ejecuta la aplicación (F5) et voilà, ya tenemos los permisos suficientes para ejecutar la lógica de negocio del back-end.
9. Referencias.
10. Conclusiones.
Hemos visto una solución simple, poco intrusiva y poco costosa de SSO centralizado, securizando un front-end AngularJS y un back-end Spring Boot con el soporte de keycloak.
Un saludo.
François
No tener en cuenta los tags bold html y en el código proporcionado en el articulo. Tener en cuenta lo subido en el repositorio git.
Gracias.
Estupendo tutorial. Muchas gracias por compartirlo.