This commit is contained in:
luis cespedes 2025-05-13 17:06:16 -04:00
parent c84c9a95c8
commit 1ca16b0e94
2 changed files with 1476 additions and 963 deletions

View File

@ -1,963 +0,0 @@
# 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
<html>
<body>
<script>
parent.postMessage(location.href, location.origin);
</script>
</body>
</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<KeycloakProfile | null> {
return this.keycloak.loadUserProfile();
}
public login(): void {
this.keycloak.login();
}
public logout(): void {
this.keycloak.logout();
}
public isLoggedIn(): Promise<boolean> {
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<boolean | UrlTree> {
// 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
<div class="container mt-5">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h2>Demo Keycloak con LDAP - Correos.com</h2>
</div>
<div class="card-body">
<div *ngIf="isLoggedIn; else loginButton">
<h3>Bienvenido, {{ userProfile?.firstName }} {{ userProfile?.lastName }}</h3>
<p>Email: {{ userProfile?.email }}</p>
<p>Nombre de Usuario: {{ userProfile?.username }}</p>
<h4>Tus Roles:</h4>
<ul>
<li *ngFor="let role of userRoles">{{ role }}</li>
</ul>
<button class="btn btn-danger" (click)="logout()">Cerrar Sesión</button>
</div>
<ng-template #loginButton>
<p>Por favor inicia sesión para acceder al sistema</p>
<button class="btn btn-primary" (click)="login()">Iniciar Sesión</button>
</ng-template>
</div>
</div>
</div>
</div>
</div>
```
Agrega Bootstrap a `src/index.html`:
```html
<head>
<!-- Otras etiquetas -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
```
### 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.

File diff suppressed because it is too large Load Diff