Protege tu api .NET y tu aplicación Angular con Keycloak(Pt. 1)
Identity and Access Management(IAM de aquí en adelante), son marcos de trabajo (frameworks) usados para autenticar la identidad de un usuario y sus privilegios. Un IAM valida que el usuario tenga acceso a los archivos, redes y otros recursos a los cuales ha solicitado acceso.
Keycloak es una solución open source para Identity and Access Management que apunta a aplicaciones modernas y servicios. Facilita el asegurar las aplicaciones y servicios con muy poco (o no) código.
Entre algunas de sus características encontramos :
- SSO : único inicio de sesión para múltiples aplicaciones.
- Inicio de sesión con proveedores de redes sociales : además también con cualquier proveedor oauth/oidc.
- Federación de usuarios : Keycloak tiene soporte incluido para conectarse a directorios LDAP ó Active Directory . Además puedes implementar tu propio proveedor en caso de tener usuarios en otro almacén como por ejemplo: bases de datos relacionales.
- Gatekeeper : Keycloak puede ser usado como un proxy para asegurar tus aplicaciones sin necesida de modificarlas.
Aquí vamos a usarlo para proteger el acceso a una aplicación SPA Angular y el consumo de un recurso webapi .NET (en este caso .NET5).
En esta entrega cubrimos la configuración de Keycloak y el backend. Para la proxima entrega seguimos con la aplicación Angular.
Empecemos, shall we ?
Nota
Les pido un poco de paciencia, pues a diferencia de mis otros artículos, este es un poquito mas extenso, pero nos dará visibilidad total de protección de su aplicación (tanto back como front).
Primero lo primero
Levantaremos una instancia de Keycloak con Docker (por simplicidad) y vamos a configurar la misma creando usuarios, roles y aplicaciones cliente para la webapi y para la SPA Angular.
Vamos a iniciar sesion en la url http://localhost:8080 e ingresamos con el nombre de usuario “admin” y contraseña “admin” despues de levantar el contenedor con el siguiente comando:
docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak
Para los impacientes, hay una imagen de docker ya configurada con todos los cambios que se sugieren en este artículo, podria reemplazar el comando de arriba por este (las credenciales para el admin son : “admin:admin” y para el usuario john : “john:12345678”).
docker run -p 8080:8080 lekamor2006/net-ng-keycloak
Un realm administra un conjunto de usuarios, credenciales, roles y grupos. Keycloak viene con un realm llamado Master, pero vamos a crear otro y dejamos Master para la gestión propia de Keycloak. A continuación creamos un realm llamado “iam”.
Ahora necesitamos crear un Client y un Client Scope : el Client representa la aplicación cliente que solicita autenticar un usuario; El Client Scope es una forma de limitar los roles que se declaran dentro de un token (access o id). Cuando un Client solicita que un usuario sea autenticado, el access token que recibe de vuelta va a contener sólo los atributos que se especifiquen en el Client Scope, de esta forma se limitan los permisos para cada access token generado en vez de darle acceso al cliente a todos los permisos del usuario.
Crearemos 2 aplicaciones cliente : una para la aplicación Angular llamada “frontend” y otra para la Webapi .NET6 llamada “webapp”. Al crear la aplicacion “frontend” no olvide especificar url raiz (Root Url) apuntando a la url desde la cual se sirve la aplicación Angular (http://localhost:4200), si no hacemos esto, entonces la aplicación no podrá interactuar con Keycloak ya que este necesita saber desde donde está siendo invocado.
Luego vamos a crear un ClientScope llamado “basic_app” y vamos mapear los roles del usuario a este ClientScope que van a estar disponibles como claims en el token JWT. No pasen por alto que entre los mappers del ClientScope, tambien coloque uno llamado audience que representa a quien esta destinado el recurso y en este caso seleccione la webapp.
En este punto solo nos restan algunas cosas que hacer :
- Asociar el ClientScope a la aplicacion cliente frontend : lo que buscamos es que los tokens emitidos para este cliente contengan la audiencia del backend.
- Crear uno o dos roles.
- Crear un usuario y asignarle los roles.
Recuerde que todas estas actividades estan siendo realizadas en el realm “iam” y no en el realm “Master”.
Lista la asignación de ClientScopes al cliente frontend, procedemos a crear los roles appuser y operator y el usuario john (el nombre de tu usuario puede ser cualquiera y debes tomar nota de la contraseña que luego la vamos a usar para probar que esta todo bien configurado).
Es hora de validar que Keycloak autentica un usuario y en efecto devuelve como claims los roles asociados al mismo. Este paso es sencillo : vamos a hacer una llamada post al endpoint de tokens del realm seleccionado pasando usuario, contraseña, aplicacion cliente y grant_type. En este punto solo debemos pegarle al endpoint http://localhost:8080/auth/realms/iam/protocol/openid-connect/token (En esta url “iam” es el realm, en la ultima version probada para este ejercicio, el nombre del realm es case sensitive) podemos hacerlo con Postman, Insomnia, Curl, etc.
Vamos a inspeccionar ese token a ver que contiene, de preferencia usen el sitio jwt.io y peguen el access_token
Como pueden observar en el token tenemos el ClientScope basic_app asociado a la aplicación cliente “frontend” y trae los roles que se asociaron al usuario.
Vamos por el backend!!
Vamos a crear una webapi .NET6, expondremos un único endpoint que nos devuelva una lista de números y este recurso solo responderá si la solicitud contiene un access token generado para el mismo (audiencia webapp).
Empecemos por crear el proyecto para el backend
dotnet new webapi -n SecuredBackend
Ingresamos a la carpeta SecuredBackend e instalamos el siguiente paquete:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Ahora modificamos le Program.cs para añadir los servicios de autenticación.
Los valores para “Jwt:Authority” y “Jwt:Audience” los agregamos al archivo appsettings.json, el Authority debe apuntar a nuestra instancia de Keycloak y el realm “iam”
Falta añadir app.UseAuthentication() y app.UseAuthorization(), en este mismo orden.
Para procesar las solicitudes, creamos un RouteEndpoint para procesar la peticion get a la ruta “/api/numero” y retornar un array de numeros aleatorios
Ejecutemos el backend y probemos primero sin token y despues con un token generado como ya vimos antes
Con esta parte concluimos la configuración de Keycloak y nuestro backend para autenticar las solcitudes que vienen con los tokens jwt emitidos por Keycloak. En la proxima parte veremos como preparar nuestra aplicación Angular para usar los tokens y consumir el backend.
Aqui les dejo el repo con el Backend y frontend (Github).
Parte 2 : Aplicación Angular