# Tutorial: Implementación de Keycloak con LDAP para Angular Este tutorial explica cómo configurar un sistema de autenticación completo utilizando Keycloak como proveedor de identidad, OpenLDAP como directorio de usuarios y una aplicación Angular que consume estos servicios. ## Índice 1. [Preparación del entorno Ubuntu](#1-preparaci%C3%B3n-del-entorno-ubuntu) 2. [Instalación y configuración de OpenLDAP](#2-instalaci%C3%B3n-y-configuraci%C3%B3n-de-openldap) 3. [Crear estructura LDAP para correos.com](#3-crear-estructura-ldap-para-correoscom) 4. [Instalación y configuración de Keycloak](#4-instalaci%C3%B3n-y-configuraci%C3%B3n-de-keycloak) 5. [Configuración de Keycloak en la interfaz web](#5-configuraci%C3%B3n-de-keycloak-en-la-interfaz-web) 6. [Configuración de una aplicación Angular](#6-configuraci%C3%B3n-de-una-aplicaci%C3%B3n-angular) 7. [Arquitectura del sistema](#7-arquitectura-del-sistema) 8. [Resolución de problemas comunes](#8-resoluci%C3%B3n-de-problemas-comunes) 9. [Verificación y prueba del sistema](#9-verificaci%C3%B3n-y-prueba-del-sistema) 10. [Resumen](#10-resumen) ## 1. Preparación del entorno Ubuntu Primero, actualizamos el sistema e instalamos Java: ```bash sudo apt update sudo apt upgrade -y sudo apt install openjdk-17-jdk -y ``` Verifica la instalación de Java: ```bash java -version ``` ## 2. Instalación y configuración de OpenLDAP ### Instalar OpenLDAP y utilidades ```bash sudo apt install slapd ldap-utils -y ``` Durante la instalación, se te pedirá configurar una contraseña de administrador para LDAP. ### Reconfigurar LDAP con el dominio correcto ```bash sudo dpkg-reconfigure slapd ``` En la configuración: 1. "¿Omitir configuración del servidor LDAP?" → No 2. "Nombre de dominio DNS:" → **correos.com** 3. "Nombre de la organización:" → Correos Org 4. "Contraseña de administrador:" → [tu contraseña segura] 5. "Confirmar contraseña:" → [repetir la contraseña] 6. "Motor de base de datos:" → MDB 7. "¿Quiere que se elimine la base de datos cuando se purgue slapd?" → No 8. "¿Mover la base de datos antigua?" → Sí ### Verificar que LDAP se esté ejecutando correctamente ```bash sudo systemctl status slapd ``` ### Comprobar la conexión LDAP básica ```bash ldapsearch -x -H ldap://localhost -b dc=correos,dc=com -D "cn=admin,dc=correos,dc=com" -W ``` ### Instalar phpLDAPadmin para la gestión gráfica ```bash sudo apt install phpldapadmin -y ``` ### Configurar phpLDAPadmin Edita el archivo de configuración: ```bash sudo nano /etc/phpldapadmin/config.php ``` Busca y modifica las siguientes líneas: ```php $servers->setValue('server','host','127.0.0.1'); $servers->setValue('server','base',array('dc=correos,dc=com')); $servers->setValue('login','bind_id','cn=admin,dc=correos,dc=com'); ``` Y cambia esta línea: ```php $servers->setValue('login','anon_bind',true); ``` por: ```php $servers->setValue('login','anon_bind',false); ``` Reinicia el servidor web: ```bash sudo systemctl restart apache2 ``` ## 3. Crear estructura LDAP para correos.com ### Crear unidades organizativas Crea un archivo para las unidades organizativas: ```bash nano ~/ou.ldif ``` Con el siguiente contenido: ```ldif dn: ou=grupos,dc=correos,dc=com objectClass: organizationalUnit ou: grupos dn: ou=usuarios,dc=correos,dc=com objectClass: organizationalUnit ou: usuarios ``` Aplica los cambios: ```bash ldapadd -x -D cn=admin,dc=correos,dc=com -W -f ~/ou.ldif ``` ### Crear grupos LDAP Crea un archivo para los grupos: ```bash nano ~/grupos.ldif ``` Con el siguiente contenido: ```ldif dn: cn=administradores,ou=grupos,dc=correos,dc=com objectClass: posixGroup cn: administradores gidNumber: 1000 dn: cn=desarrolladores,ou=grupos,dc=correos,dc=com objectClass: posixGroup cn: desarrolladores gidNumber: 1001 dn: cn=usuarios,ou=grupos,dc=correos,dc=com objectClass: posixGroup cn: usuarios gidNumber: 1002 ``` Aplica los cambios: ```bash ldapadd -x -D cn=admin,dc=correos,dc=com -W -f ~/grupos.ldif ``` ### Crear usuarios LDAP Primero, genera contraseñas encriptadas para los usuarios: ```bash slappasswd -s "password123" ``` Anota el hash resultante para usarlo en el siguiente archivo. Crea un archivo para los usuarios: ```bash nano ~/usuarios.ldif ``` Con el siguiente contenido (reemplazando {HASH} con el hash que generaste): ```ldif dn: uid=admin,ou=usuarios,dc=correos,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: admin sn: Admin givenName: Admin cn: Admin User displayName: Admin User uidNumber: 1000 gidNumber: 1000 userPassword: {HASH} loginShell: /bin/bash homeDirectory: /home/admin mail: admin@correos.com dn: uid=developer,ou=usuarios,dc=correos,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: developer sn: Developer givenName: Dev cn: Dev User displayName: Developer User uidNumber: 1001 gidNumber: 1001 userPassword: {HASH} loginShell: /bin/bash homeDirectory: /home/developer mail: developer@correos.com dn: uid=user,ou=usuarios,dc=correos,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: user sn: User givenName: Normal cn: Normal User displayName: Normal User uidNumber: 1002 gidNumber: 1002 userPassword: {HASH} loginShell: /bin/bash homeDirectory: /home/user mail: user@correos.com ``` Aplica los cambios: ```bash ldapadd -x -D cn=admin,dc=correos,dc=com -W -f ~/usuarios.ldif ``` ### Asociar usuarios a grupos Crea un archivo para las membresías: ```bash nano ~/miembros.ldif ``` Con el siguiente contenido: ```ldif dn: cn=administradores,ou=grupos,dc=correos,dc=com changetype: modify add: memberUid memberUid: admin dn: cn=desarrolladores,ou=grupos,dc=correos,dc=com changetype: modify add: memberUid memberUid: developer dn: cn=usuarios,ou=grupos,dc=correos,dc=com changetype: modify add: memberUid memberUid: user ``` Aplica los cambios: ```bash ldapmodify -x -D cn=admin,dc=correos,dc=com -W -f ~/miembros.ldif ``` ### Verificar la estructura LDAP ```bash ldapsearch -x -H ldap://localhost -b dc=correos,dc=com -D "cn=admin,dc=correos,dc=com" -W ``` ## 4. Instalación y configuración de Keycloak ### Descargar e instalar Keycloak ```bash # Crear directorio para Keycloak mkdir -p ~/keycloak cd ~/keycloak # Descargar la última versión de Keycloak wget https://github.com/keycloak/keycloak/releases/download/21.1.1/keycloak-21.1.1.tar.gz # Extraer el archivo tar -xvzf keycloak-21.1.1.tar.gz # Mover a una ubicación más adecuada sudo mv keycloak-21.1.1 /opt/keycloak # Crear un usuario para Keycloak sudo useradd -r -s /sbin/nologin keycloak # Asignar permisos sudo chown -R keycloak:keycloak /opt/keycloak ``` ### Configurar usuario administrador inicial para Keycloak Crea un archivo de propiedades: ```bash sudo nano /opt/keycloak/conf/keycloak.conf ``` Agrega estas líneas: ``` # Configuración básica http-port=8080 https-port=8443 hostname=localhost # Configuración de administrador inicial http-enabled=true ``` ### Iniciar Keycloak en modo desarrollo ```bash cd /opt/keycloak export KEYCLOAK_ADMIN=admin export KEYCLOAK_ADMIN_PASSWORD=admin sudo -u keycloak bin/kc.sh start-dev ``` Esto iniciará Keycloak con un usuario administrador "admin" y contraseña "admin". ### Configurar Keycloak como servicio En otra terminal, crea un archivo de servicio systemd: ```bash sudo nano /etc/systemd/system/keycloak.service ``` Con el siguiente contenido: ```ini [Unit] Description=Keycloak Application Server After=network.target [Service] Type=idle User=keycloak Group=keycloak Environment="KEYCLOAK_ADMIN=admin" Environment="KEYCLOAK_ADMIN_PASSWORD=admin" ExecStart=/opt/keycloak/bin/kc.sh start-dev TimeoutStartSec=600 TimeoutStopSec=600 [Install] WantedBy=multi-user.target ``` En el futuro, podrás habilitar e iniciar el servicio con: ```bash sudo systemctl daemon-reload sudo systemctl enable keycloak sudo systemctl start keycloak ``` ## 5. Configuración de Keycloak en la interfaz web Ahora puedes acceder a la consola de administración de Keycloak en http://localhost:8080/admin/ e iniciar sesión con: - Usuario: `admin` - Contraseña: `admin` ### Crear un nuevo Reino (Realm) 1. Haz clic en el menú desplegable superior izquierdo que dice "master" 2. Selecciona "Create Realm" 3. Ingresa el nombre: `angular-app` 4. Haz clic en "Create" ### Configurar la Federación de Usuarios LDAP 1. En el menú lateral izquierdo, selecciona "User Federation" 2. Haz clic en "Add provider" → "ldap" 3. Completa los siguientes campos: - Console Display Name: `LDAP` - Vendor: `Other` - Connection URL: `ldap://localhost:389` - Enable StartTLS: `OFF` - Bind Type: `simple` - Bind DN: `cn=admin,dc=correos,dc=com` - Bind Credential: (la contraseña de admin LDAP) - Edit Mode: `WRITABLE` - Users DN: `ou=usuarios,dc=correos,dc=com` - Username LDAP attribute: `uid` - RDN LDAP attribute: `uid` - UUID LDAP attribute: `entryUUID` - User Object Classes: `inetOrgPerson, posixAccount` - Custom User LDAP Filter: (dejar en blanco) - Search Scope: `One Level` 4. Haz clic en "Test connection" y "Test authentication" para verificar 5. Guarda la configuración 6. En la pantalla del proveedor LDAP, ve a la pestaña "Synchronization" 7. Haz clic en "Sync all users" ### Configurar el Mapeo de Grupos LDAP 1. En la pantalla del proveedor LDAP, ve a la pestaña "Mappers" 2. Haz clic en "Create" 3. Completa: - Name: `group-mapper` - Mapper Type: `group-ldap-mapper` - LDAP Groups DN: `ou=grupos,dc=correos,dc=com` - Group Object Classes: `posixGroup` - Membership LDAP Attribute: `memberUid` - Group Name LDAP Attribute: `cn` - User Roles Retrieve Strategy: `LOAD_GROUPS_BY_MEMBER_ATTRIBUTE` - Member-Of LDAP Attribute: `memberOf` - Mapped Group Attributes: (dejar en blanco) - Drop non-existing groups during sync: `ON` 4. Haz clic en "Save" 5. En la pantalla del mapper, haz clic en "Sync LDAP Groups to Keycloak" ### Crear un Cliente para Angular 1. En el menú lateral izquierdo, selecciona "Clients" 2. Haz clic en "Create client" 3. Completa: - Client type: `OpenID Connect` - Client ID: `angular-app` - Name: `Angular Application` - Haz clic en "Next" 4. En la siguiente pantalla: - Client authentication: `ON` - Authorization: `OFF` - Haz clic en "Next" 5. En la siguiente pantalla: - Root URL: `http://localhost:4200` - Home URL: `/` - Valid redirect URIs: `http://localhost:4200/*` - Web origins: `http://localhost:4200` - Haz clic en "Save" 6. En la pestaña "Credentials" del cliente, copia el "Client secret" (lo necesitarás para la aplicación Angular) ## 6. Configuración de una aplicación Angular Primero, instala Node.js y npm: ```bash curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs ``` ### Crear una aplicación Angular ```bash # Instalar Angular CLI npm install -g @angular/cli # Crear una nueva aplicación ng new angular-keycloak-app cd angular-keycloak-app # Instalar la biblioteca para integrar Keycloak npm install keycloak-angular keycloak-js ``` ### Configurar Keycloak en Angular Crea un archivo de configuración en `src/assets/keycloak.json`: ```json { "realm": "angular-app", "auth-server-url": "http://localhost:8080/", "resource": "angular-app", "credentials": { "secret": "TU_CLIENT_SECRET_AQUÍ" } } ``` Modifica el archivo `src/app/app.module.ts`: ```typescript import { NgModule, APP_INITIALIZER } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; function initializeKeycloak(keycloak: KeycloakService) { return () => keycloak.init({ config: { url: 'http://localhost:8080', realm: 'angular-app', clientId: 'angular-app' }, initOptions: { onLoad: 'check-sso', silentCheckSsoRedirectUri: window.location.origin + '/assets/silent-check-sso.html' } }); } @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, KeycloakAngularModule ], providers: [ { provide: APP_INITIALIZER, useFactory: initializeKeycloak, multi: true, deps: [KeycloakService] } ], bootstrap: [AppComponent] }) export class AppModule { } ``` Crea un archivo `src/assets/silent-check-sso.html`: ```html ``` ### Crear un servicio de autenticación ```bash ng generate service auth ``` Edita `src/app/auth.service.ts`: ```typescript import { Injectable } from '@angular/core'; import { KeycloakService } from 'keycloak-angular'; import { KeycloakProfile } from 'keycloak-js'; @Injectable({ providedIn: 'root' }) export class AuthService { constructor(private keycloak: KeycloakService) { } public getLoggedUser(): Promise { return this.keycloak.loadUserProfile(); } public login(): void { this.keycloak.login(); } public logout(): void { this.keycloak.logout(); } public isLoggedIn(): Promise { return this.keycloak.isLoggedIn(); } public getRoles(): string[] { return this.keycloak.getUserRoles(); } } ``` ### Crear un guardia para rutas protegidas ```bash ng generate guard auth ``` Edita `src/app/auth.guard.ts`: ```typescript import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router'; import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular'; @Injectable({ providedIn: 'root' }) export class AuthGuard extends KeycloakAuthGuard { constructor( protected override readonly router: Router, protected readonly keycloak: KeycloakService ) { super(router, keycloak); } public async isAccessAllowed( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Promise { // Verifica si el usuario está autenticado if (!this.authenticated) { await this.keycloak.login({ redirectUri: window.location.origin + state.url, }); return false; } // Obtiene los roles requeridos desde la ruta const requiredRoles = route.data['roles']; // Permite el acceso si no hay roles requeridos if (!requiredRoles || requiredRoles.length === 0) { return true; } // Verifica si el usuario tiene al menos uno de los roles requeridos return requiredRoles.some((role: string) => this.roles.includes(role)); } } ``` ### Configurar las rutas con protección Modifica `src/app/app-routing.module.ts`: ```typescript import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AuthGuard } from './auth.guard'; import { AppComponent } from './app.component'; const routes: Routes = [ { path: 'admin', component: AppComponent, canActivate: [AuthGuard], data: { roles: ['administradores'] } }, { path: 'developer', component: AppComponent, canActivate: [AuthGuard], data: { roles: ['desarrolladores'] } }, { path: 'user', component: AppComponent, canActivate: [AuthGuard], data: { roles: ['usuarios'] } }, { path: '', component: AppComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } ``` ### Modificar el componente principal Edita `src/app/app.component.ts`: ```typescript import { Component, OnInit } from '@angular/core'; import { AuthService } from './auth.service'; import { KeycloakProfile } from 'keycloak-js'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { title = 'angular-keycloak-app'; isLoggedIn = false; userProfile: KeycloakProfile | null = null; userRoles: string[] = []; constructor(private authService: AuthService) {} async ngOnInit() { this.isLoggedIn = await this.authService.isLoggedIn(); if (this.isLoggedIn) { this.userProfile = await this.authService.getLoggedUser(); this.userRoles = this.authService.getRoles(); } } login() { this.authService.login(); } logout() { this.authService.logout(); } } ``` Edita `src/app/app.component.html`: ```html

Demo Keycloak con LDAP - Correos.com

Bienvenido, {{ userProfile?.firstName }} {{ userProfile?.lastName }}

Email: {{ userProfile?.email }}

Nombre de Usuario: {{ userProfile?.username }}

Tus Roles:

  • {{ role }}

Por favor inicia sesión para acceder al sistema

``` Agrega Bootstrap a `src/index.html`: ```html ``` ### Ejecutar la aplicación ```bash ng serve ``` Abre http://localhost:4200 en tu navegador. ## 7. Arquitectura del sistema La arquitectura del sistema está compuesta por los siguientes componentes: - **OpenLDAP**: Directorio de usuarios y grupos (puerto 389) - **phpLDAPadmin**: Interfaz gráfica para administrar LDAP (puerto 80) - **Keycloak**: Servidor de autenticación y autorización (puerto 8080) - **Aplicación Angular**: Cliente que utiliza el SSO de Keycloak (puerto 4200) La estructura del directorio LDAP para correos.com es: - dc=correos,dc=com (raíz del directorio) - ou=usuarios (unidad organizativa para usuarios) - uid=admin (usuario administrador) - uid=developer (usuario desarrollador) - uid=user (usuario normal) - ou=grupos (unidad organizativa para grupos) - cn=administradores (grupo de administradores) - cn=desarrolladores (grupo de desarrolladores) - cn=usuarios (grupo de usuarios) ## 8. Resolución de problemas comunes ### Problema: "ldap_bind: Invalid credentials (49)" Este error ocurre cuando intentas conectarte a LDAP con credenciales incorrectas. Para resolverlo: 1. Verifica que estás usando el dominio correcto: `dc=correos,dc=com` 2. Asegúrate de usar el DN correcto: `cn=admin,dc=correos,dc=com` 3. Comprueba que la contraseña de administrador es correcta Si olvidaste la contraseña, puedes restablecerla: ```bash sudo dpkg-reconfigure slapd ``` O también: ```bash sudo slappasswd # Copia el hash generado sudo nano /etc/ldap/slapd.d/cn=config/olcDatabase={1}mdb.ldif # Busca olcRootPW y reemplaza el valor con el nuevo hash sudo systemctl restart slapd ``` ### Problema: No puedes conectarte a LDAP en absoluto ```bash # Verifica que el servicio esté ejecutándose sudo systemctl status slapd # Reinicia el servicio si es necesario sudo systemctl restart slapd # Verifica que el puerto esté abierto sudo netstat -tulpn | grep 389 ``` ### Problema: Keycloak no se inicia ```bash # Verifica los logs sudo journalctl -u keycloak # Asegúrate de que Java esté instalado correctamente java -version # Verifica los permisos sudo ls -la /opt/keycloak ``` ### Problema: La aplicación Angular no puede conectarse a Keycloak 1. Verifica que Keycloak esté en ejecución 2. Comprueba la URL del servidor Keycloak en la configuración de Angular 3. Asegúrate de que el cliente esté correctamente configurado en Keycloak 4. Verifica el Client Secret 5. Comprueba las URLs de redirección ## 9. Verificación y prueba del sistema ### Verificar que Keycloak esté sincronizando correctamente con LDAP 1. Inicia sesión en la consola de administración de Keycloak (http://localhost:8080/admin/) 2. Navega a "Users" en el reino "angular-app" 3. Deberías ver los usuarios de LDAP: admin, developer y user 4. Navega a "Groups" y verifica que los grupos de LDAP estén presentes ### Probar la aplicación Angular 1. Asegúrate de que Keycloak esté ejecutándose 2. Inicia la aplicación Angular con `ng serve` 3. Navega a http://localhost:4200 4. Haz clic en "Iniciar Sesión" 5. Deberías ser redirigido a la pantalla de inicio de sesión de Keycloak 6. Inicia sesión con uno de los usuarios LDAP: - Usuario: admin, Contraseña: password123 - Usuario: developer, Contraseña: password123 - Usuario: user, Contraseña: password123 7. Después de iniciar sesión, serás redirigido de vuelta a la aplicación 8. La aplicación mostrará tu perfil y roles ## 10. Resumen Esta configuración proporciona un sistema completo de gestión de identidades y acceso con: - **Autenticación centralizada**: Los usuarios solo necesitan recordar un conjunto de credenciales - **Gestión de usuarios unificada**: Todos los usuarios se administran en LDAP - **Control de acceso basado en roles**: Las rutas y funcionalidades pueden ser protegidas según los roles del usuario - **Experiencia de inicio de sesión único (SSO)**: Una vez autenticado, el usuario puede acceder a todas las aplicaciones integradas Este sistema es adecuado para entornos empresariales donde se requiere un control de acceso detallado y una gestión centralizada de usuarios. La implementación es nativa en un sistema Ubuntu, lo que la hace ideal para despliegues en servidores VPS o entornos similares sin necesidad de contenedores.