Integración de Keycloak con AngularJS y Spring Boot

2
16979

Í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.

keycloak-angularjs-springboot_00

Una vez arrancado …

keycloak-angularjs-springboot_01

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)

keycloak-angularjs-springboot_02

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.

keycloak-angularjs-springboot_03

Pinchando sobre la opción, aparecerá a la derecha un formulario donde indicaremos el nombre del nuevo realm que queremos crear.

keycloak-angularjs-springboot_04

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.

keycloak-angularjs-springboot_05

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.

keycloak-angularjs-springboot_06


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

keycloak-angularjs-springboot_07


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.

keycloak-angularjs-springboot_08

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

    keycloak-angularjs-springboot_09

    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.

    keycloak-angularjs-springboot_10

    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.

    keycloak-angularjs-springboot_11

    Descargamos el archivo JSON y lo guardamos en la ruta /keycloak/keycloak.json por debajo de la webapp.

    keycloak-angularjs-springboot_12

    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.

    keycloak-angularjs-springboot_13

    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.

    keycloak-angularjs-springboot_14

    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.

    keycloak-angularjs-springboot_15

    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.

    keycloak-angularjs-springboot_16

    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.
  • keycloak-angularjs-springboot_17

    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.

    keycloak-angularjs-springboot_18

    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.

    keycloak-angularjs-springboot_19


    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

    2 COMENTARIOS

    1. 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.

    DEJA UNA RESPUESTA

    Por favor ingrese su comentario!

    He leído y acepto la política de privacidad

    Por favor ingrese su nombre aquí

    Información básica acerca de la protección de datos

    • Responsable:
    • Finalidad:
    • Legitimación:
    • Destinatarios:
    • Derechos:
    • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad