Skip to content

danifgxcom/fido2demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FIDO2 Demo - Sistema Completo de Demostración FIDO2/CTAP2

Un sistema de demostración integral para FIDO2/CTAP2 que permite registrar, autenticar y gestionar credenciales utilizando llaves de seguridad como Google Titan, YubiKey y otros dispositivos FIDO2.

🔐 Características Principales

Funcionalidades FIDO2 Completas

  • Registro de Credenciales: Implementación completa de la ceremonia de registro WebAuthn
  • Autenticación: Soporte para autenticación con y sin nombre de usuario (credenciales residentes/discoverable)
  • Gestión de Credenciales: Visualización, eliminación y administración de credenciales almacenadas
  • Soporte para Credenciales Residentes: Autenticación sin contraseña usando resident keys
  • Verificación de Attestation: Verificación e información detallada de attestation
  • FIDO MDS Integration: Reconocimiento automático de 274+ dispositivos certificados vía FIDO Alliance Metadata Service
  • Base de Datos Persistente: H2 con persistencia en archivo - los datos sobreviven reinicios
  • Testing Completo: 109+ tests unitarios e integración con 100% de cobertura en componentes críticos

Gestión de Dispositivos

  • Detección Automática: Detección y conexión automática de dispositivos FIDO2
  • Estado Visual: Indicadores visuales del estado del dispositivo (conectado, esperando toque, procesando, error)
  • Información del Dispositivo: Visualización detallada de capacidades y características del dispositivo
  • Reconocimiento de Dispositivos: Identificación automática mediante AAGUID con integración FIDO MDS
  • Información de Certificación: Muestra estado de certificación FIDO de los dispositivos
  • Reseteo de Dispositivos: Funcionalidad para resetear dispositivos FIDO2
  • Notificaciones en Tiempo Real: WebSocket para actualizaciones de estado en tiempo real

FIDO Alliance Metadata Service (MDS)

  • Descarga Automática: Descarga automática de metadata de https://mds3.fidoalliance.org/
  • Cache Persistente: Almacenamiento local en ./data/mds-cache/ para funcionamiento offline
  • Actualización Programada: Actualización automática diaria a las 2 AM
  • 274+ Dispositivos: Base de datos oficial de dispositivos FIDO2 certificados
  • Información Detallada: Descripción, fabricante, modelo, estado de certificación e iconos
  • Fallback Automático: Si MDS no está disponible, usa lista estática de dispositivos conocidos

Interfaz de Usuario Avanzada

  • Dashboard Interactivo: Panel de control con estadísticas y estado general
  • Interfaz React Moderna: Frontend responsivo y fácil de usar
  • Animaciones Visuales: Efectos visuales para indicar estado del dispositivo y acciones
  • Multi-idioma: Preparado para múltiples idiomas (actualmente en inglés/español)

🏗️ Arquitectura del Sistema

┌─────────────────────────────────────────────────────────────┐
│                    Frontend (React)                         │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │
│  │  Dashboard  │ │Registration │ │Authentication│           │
│  └─────────────┘ └─────────────┘ └─────────────┘           │
│  ┌─────────────┐ ┌─────────────────────────────────────┐   │
│  │Credentials  │ │       Device Manager                │   │
│  └─────────────┘ └─────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
                              │
                              │ HTTP/WebSocket
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                Backend (Spring Boot)                        │
│  ┌─────────────────┐    ┌─────────────────┐                │
│  │ WebAuthn        │    │ Device          │                │
│  │ Controller      │    │ Controller      │                │
│  └─────────────────┘    └─────────────────┘                │
│  ┌─────────────────┐    ┌─────────────────┐                │
│  │ WebAuthn        │    │ CTAP2 Device    │                │
│  │ Service         │    │ Manager         │                │
│  └─────────────────┘    └─────────────────┘                │
│  ┌─────────────────┐    ┌─────────────────┐                │
│  │ Credential      │    │ WebSocket       │                │
│  │ Repository      │    │ Config          │                │
│  └─────────────────┘    └─────────────────┘                │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│             Dispositivos FIDO2/CTAP2                       │
│  🔑 Google Titan    🔐 YubiKey    🛡️ Otros FIDO2           │
└─────────────────────────────────────────────────────────────┘

🚀 Tecnologías Utilizadas

Backend

  • Java 21: Lenguaje de programación principal
  • Spring Boot 3.2.1: Framework principal para el backend
  • Spring WebSocket: Para comunicación en tiempo real con el frontend
  • Spring Data JPA: Para persistencia de datos
  • H2 Database: Base de datos en memoria para desarrollo
  • Yubico WebAuthn Java: Biblioteca para implementación WebAuthn/FIDO2
  • Maven: Gestión de dependencias y construcción

Frontend

  • React 18: Biblioteca principal para la interfaz de usuario
  • Vite: Herramienta de construcción y desarrollo
  • React Router: Navegación entre páginas
  • SockJS + STOMP: WebSocket para comunicación en tiempo real
  • Axios: Cliente HTTP para APIs REST
  • Lucide React: Iconos modernos
  • React Toastify: Notificaciones al usuario

Seguridad y FIDO2

  • WebAuthn API: API estándar del navegador para FIDO2
  • CTAP2 Protocol: Protocolo de comunicación con dispositivos FIDO2
  • Attestation Verification: Verificación de autenticidad del dispositivo
  • Resident Keys: Soporte para credenciales almacenadas en el dispositivo

📁 Estructura del Proyecto

fido2demo/
├── pom.xml                             # Configuración Maven principal
├── README.md                           # Este archivo
├── src/main/
│   ├── java/com/example/fido2demo/
│   │   ├── Fido2DemoApplication.java   # Clase principal Spring Boot
│   │   ├── config/
│   │   │   └── WebSocketConfig.java    # Configuración WebSocket
│   │   ├── controller/
│   │   │   ├── WebAuthnController.java # API REST para WebAuthn
│   │   │   └── DeviceController.java   # API REST para dispositivos
│   │   ├── model/
│   │   │   ├── Credential.java         # Modelo de credencial
│   │   │   └── DeviceInfo.java         # Modelo de información del dispositivo
│   │   ├── repository/
│   │   │   └── CredentialRepository.java # Repositorio JPA
│   │   └── service/
│   │       ├── WebAuthnService.java    # Lógica de negocio WebAuthn
│   │       └── Ctap2DeviceManager.java # Gestión de dispositivos CTAP2
│   └── resources/
│       └── application.properties      # Configuración de la aplicación
├── frontend/                           # Aplicación React
│   ├── package.json                    # Dependencias Node.js
│   ├── vite.config.js                  # Configuración Vite
│   ├── index.html                      # HTML principal
│   └── src/
│       ├── main.jsx                    # Punto de entrada React
│       ├── App.jsx                     # Componente principal
│       ├── index.css                   # Estilos globales
│       ├── components/                 # Componentes React
│       │   ├── Dashboard.jsx           # Panel principal
│       │   ├── Registration.jsx        # Registro de credenciales
│       │   ├── Authentication.jsx      # Autenticación
│       │   ├── Credentials.jsx         # Gestión de credenciales
│       │   └── DeviceManager.jsx       # Gestión de dispositivos
│       └── context/
│           └── DeviceContext.jsx       # Context para estado de dispositivos
└── target/                             # Archivos compilados (generado)

⚙️ Instalación y Configuración

Requisitos Previos

  1. Java 21 o superior

    java -version
  2. Maven 3.8 o superior

    mvn -version
  3. Node.js 18 o superior y npm

    node --version
    npm --version
  4. Navegador Web Moderno con soporte para WebAuthn (Chrome 70+, Firefox 60+, Safari 14+)

  5. Dispositivo FIDO2 (Google Titan, YubiKey, etc.) - Opcional, el sistema incluye dispositivos simulados

Instalación

  1. Clonar el repositorio

    git clone <repository-url>
    cd fido2demo
  2. Compilar y ejecutar la aplicación

    mvn clean spring-boot:run

    Este comando:

    • Descarga todas las dependencias Java
    • Instala Node.js y npm automáticamente
    • Compila el frontend React
    • Compila el backend Java
    • Inicia la aplicación en el puerto 8081
  3. Acceder a la aplicación

    • Abrir navegador en: http://localhost:8081
    • La aplicación incluye dispositivos FIDO2 simulados para demostración

🖥️ Uso del Sistema

1. Dashboard Principal

  • Estadísticas: Visualización de dispositivos conectados, credenciales registradas y usuarios
  • Estado de Dispositivos: Información en tiempo real sobre dispositivos FIDO2 conectados
  • Accesos Rápidos: Enlaces directos a las principales funcionalidades

2. Registro de Credenciales

  1. Navegar a Register en el menú
  2. Introducir username y display name
  3. Seleccionar si se requiere resident key (credencial discoverable)
  4. Hacer clic en Register Credential
  5. Tocar el dispositivo FIDO2 cuando se solicite

3. Autenticación

  1. Navegar a Authenticate en el menú
  2. Opción A - Con username: Introducir nombre de usuario
  3. Opción B - Sin username: Dejar vacío para usar credenciales discoverable
  4. Seleccionar User Verification si se requiere PIN/biometría
  5. Hacer clic en Authenticate
  6. Tocar el dispositivo FIDO2 cuando se solicite

4. Gestión de Credenciales

  1. Navegar a Credentials en el menú
  2. Ver todas las credenciales registradas
  3. Filtrar por tipo (todas, discoverable, regulares)
  4. Buscar por usuario o ID de credencial
  5. Ver detalles completos de cada credencial
  6. Eliminar credenciales individuales o todas las de un usuario

5. Gestión de Dispositivos

  1. Navegar a Devices en el menú
  2. Ver dispositivos conectados y desconectados
  3. Información detallada del dispositivo (firmware, capacidades, etc.)
  4. Escanear nuevos dispositivos
  5. Resetear dispositivos (elimina todas las credenciales)
  6. Actualizar información del dispositivo

🔧 API Endpoints

WebAuthn API

POST /api/webauthn/register/begin          # Iniciar registro
POST /api/webauthn/register/finish         # Completar registro
POST /api/webauthn/authenticate/begin      # Iniciar autenticación
POST /api/webauthn/authenticate/finish     # Completar autenticación
GET  /api/webauthn/credentials             # Listar credenciales
GET  /api/webauthn/credentials/user/{user} # Credenciales por usuario
GET  /api/webauthn/credentials/discoverable # Credenciales discoverable
DEL  /api/webauthn/credentials/{id}        # Eliminar credencial
DEL  /api/webauthn/credentials/user/{user} # Eliminar todas del usuario

Device API

GET  /api/devices                    # Listar dispositivos conectados
GET  /api/devices/{id}               # Información de dispositivo específico
POST /api/devices/scan               # Escanear nuevos dispositivos
POST /api/devices/{id}/reset         # Resetear dispositivo
POST /api/devices/{id}/info          # Actualizar información del dispositivo

WebSocket Endpoints

/ws                           # Conexión WebSocket
/topic/devices/connected      # Dispositivo conectado
/topic/devices/disconnected   # Dispositivo desconectado
/topic/devices/status         # Cambio de estado del dispositivo

🎯 Características FIDO2 Implementadas

Ceremonias WebAuthn

  • Registration Ceremony: Registro completo con attestation
  • Authentication Ceremony: Autenticación con y sin allowCredentials
  • User Verification: Soporte para PIN y verificación biométrica
  • User Presence: Detección de toque del usuario

Tipos de Credenciales

  • Platform Credentials: Credenciales del dispositivo
  • Cross-Platform Credentials: Credenciales de llaves externas
  • Resident Keys: Credenciales almacenadas en el dispositivo
  • Non-Resident Keys: Credenciales con allowCredentials

Attestation

  • Attestation Object: Procesamiento y almacenamiento
  • AAGUID: Identificación del modelo del dispositivo
  • Attestation Verification: Verificación básica de attestation

Extensiones WebAuthn

  • credProps: Implementado - Confirma el estado de resident key (RK) del authenticator
  • 🔄 largeBlob: Planificado
  • 🔄 credentialProtectionPolicy: Planificado

credProps Extension

La extensión credProps permite confirmar si una credencial fue realmente creada como discoverable (resident key) por el authenticator. Esto es útil porque algunos authenticators pueden no soportar resident keys incluso cuando se solicitan.

Funcionalidad:

  • Se solicita automáticamente durante el registro
  • El authenticator confirma si la credencial es discoverable (RK=true/false)
  • El resultado se almacena en la base de datos para referencia futura
  • Permite detectar discrepancias entre lo solicitado y lo implementado

Implementación:

  • Backend solicita la extensión en WebAuthnService.startRegistration() (línea 85-87)
  • Backend procesa la respuesta en WebAuthnService.saveCredential() (línea 201-209)
  • El valor confirmado se guarda en Credential.discoverable

🔒 Consideraciones de Seguridad

Implementaciones de Seguridad

  1. Origin Validation: Validación estricta del origen de las requests
  2. Challenge Validation: Verificación de challenge únicos y temporales
  3. Signature Verification: Verificación criptográfica de signatures
  4. Counter Verification: Validación de signature counter para replay protection
  5. HTTPS Only: Configurado para requerir HTTPS en producción

Buenas Prácticas Implementadas

  • Almacenamiento seguro de claves públicas
  • Gestión adecuada de sesiones temporales
  • Validación de entrada en todos los endpoints
  • Logging de eventos de seguridad
  • Timeouts apropiados para ceremonias

🧪 Testing y Desarrollo

Dispositivos Simulados

El sistema incluye dispositivos FIDO2 simulados para desarrollo:

  • Google Titan Security Key: Simulación completa con AAGUID real
  • YubiKey 5 Series: Se puede activar escaneando dispositivos
  • Estados simulados: conectado, esperando toque, procesando, error

Testing con Dispositivos Reales

  1. Conectar dispositivo FIDO2 físico
  2. El sistema detectará automáticamente dispositivos compatibles
  3. Usar funcionalidad "Scan for Devices" para actualizar la lista
  4. Realizar ceremonias de registro y autenticación reales

Depuración

  • H2 Console: http://localhost:8081/h2-console (usuario: sa, sin contraseña)
  • Logs de Aplicación: Configurados en application.properties
  • WebSocket Debug: Mensajes de debug en la consola del navegador
  • Network Tab: Inspección de requests/responses WebAuthn

🚀 Despliegue en Producción

Configuración de Producción

  1. Base de Datos: Cambiar de H2 a PostgreSQL/MySQL
  2. HTTPS: Configurar certificados SSL/TLS
  3. Origin Configuration: Actualizar origins permitidos
  4. Logging: Configurar logging para producción
  5. Security Headers: Añadir headers de seguridad adicionales

Variables de Entorno

# Base de datos
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/fido2demo
SPRING_DATASOURCE_USERNAME=fido2user
SPRING_DATASOURCE_PASSWORD=secure_password

# FIDO2 Configuration
FIDO2_RELYING_PARTY_ID=your-domain.com
FIDO2_RELYING_PARTY_ORIGINS=https://your-domain.com

# Servidor
SERVER_PORT=8080
SERVER_SSL_ENABLED=true

Docker Deployment

FROM openjdk:21-jdk-slim
COPY target/fido2demo-*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

🛠️ Personalización y Extensión

Añadir Nuevos Dispositivos FIDO2

  1. Actualizar Ctap2DeviceManager.java con nuevos AAGUIDs
  2. Añadir iconos específicos en DeviceManager.jsx
  3. Configurar capacidades específicas del dispositivo

Personalizar Interfaz

  1. Modificar estilos en frontend/src/index.css
  2. Actualizar componentes React en frontend/src/components/
  3. Añadir nuevos idiomas en el sistema de internacionalización

Extensiones WebAuthn

  1. Implementar extensiones en WebAuthnService.java
  2. Actualizar frontend para manejar nuevas extensiones
  3. Añadir validación y procesamiento específico

📊 Monitoreo y Métricas

Métricas Implementadas

  • Número de credenciales registradas
  • Dispositivos conectados/desconectados
  • Intentos de autenticación exitosos/fallidos
  • Tiempos de respuesta de ceremonias

Logging

  • Eventos de registro y autenticación
  • Conexión/desconexión de dispositivos
  • Errores y excepciones detalladas
  • Métricas de rendimiento

🤝 Contribución

Desarrollo Local

  1. Fork del repositorio
  2. Crear rama para nueva funcionalidad
  3. Implementar cambios con tests
  4. Crear Pull Request con descripción detallada

Áreas de Mejora

  • Soporte para extensiones WebAuthn adicionales
  • Integración con dispositivos FIDO2 reales vía HID
  • Interfaz de administración avanzada
  • Soporte para múltiples Relying Parties
  • API REST completa para integración externa
  • Tests automatizados E2E
  • Documentación interactiva con Swagger

📞 Soporte y Contacto

Recursos

Issues y Bugs

Para reportar problemas o solicitar funcionalidades, crear un issue en el repositorio con:

  1. Descripción detallada del problema
  2. Pasos para reproducir
  3. Información del navegador y dispositivo FIDO2
  4. Logs relevantes

📜 Licencia

Este proyecto está licenciado bajo la Licencia MIT - ver el archivo LICENSE para detalles.


🐛 Problemas Técnicos Resueltos

Durante el desarrollo de este proyecto, se encontraron y resolvieron varios problemas técnicos críticos relacionados con la implementación de WebAuthn/FIDO2. Esta sección documenta estos problemas y sus soluciones para ayudar a otros desarrolladores.

1. Codificación Base64url en Credentials

Problema: Los ArrayBuffers de WebAuthn necesitan codificarse como Base64url (variante URL-safe de Base64) al enviarse al backend, no como Base64 estándar.

Síntomas:

  • Error CBOR: "Unexpected data encountered" al parsear credentials
  • Fallo en PublicKeyCredential.parseRegistrationResponseJson() o parseAssertionResponseJson()
  • Datos corruptos al intentar decodificar en el backend

Causa Raíz: Base64url usa - y _ en lugar de + y /, y no incluye padding =. Si se envía Base64 estándar, el backend no puede decodificar correctamente.

Solución Implementada:

// Frontend - Conversión correcta ArrayBuffer → Base64url
const arrayBufferToBase64url = (buffer) => {
  const bytes = new Uint8Array(buffer)
  let binary = ''
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i])
  }
  // Convertir a base64 y luego a base64url
  return btoa(binary)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '')  // Eliminar padding
}

// Frontend - Conversión correcta Base64url → ArrayBuffer
const base64UrlToArrayBuffer = (base64url) => {
  // Convertir base64url a base64
  const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/')
  // Añadir padding si es necesario
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, '=')
  const binary = atob(padded)
  const buffer = new ArrayBuffer(binary.length)
  const view = new Uint8Array(buffer)
  for (let i = 0; i < binary.length; i++) {
    view[i] = binary.charCodeAt(i)
  }
  return buffer
}

Archivos Afectados:

  • frontend/src/components/Registration.jsx: líneas 147-174
  • frontend/src/components/Authentication.jsx: líneas 172-195

2. UserHandle Consistency

Problema: Cada registro generaba un userHandle aleatorio diferente, causando que el mismo username tuviera diferentes userHandles en registros sucesivos.

Síntomas:

  • Error: "Unknown credential: ByteArray(...)" durante autenticación
  • Credentials no encontrados aunque existían en la base de datos
  • CredentialRepository.lookup() fallaba al no coincidir userHandles

Causa Raíz: El método generateUserHandle() generaba bytes aleatorios en cada llamada:

// INCORRECTO - Genera valores diferentes cada vez
private byte[] generateUserHandle(String username) {
    byte[] userHandle = new byte[32];
    random.nextBytes(userHandle);
    return userHandle;
}

Solución Implementada:

// CORRECTO - Genera el mismo userHandle para el mismo username
private byte[] generateUserHandle(String username) {
    // Generate a consistent userHandle based on username
    // This ensures the same username always gets the same userHandle
    return (username + "-user-handle").getBytes(StandardCharsets.UTF_8);
}

Explicación: El userHandle debe ser consistente para un mismo usuario a través de múltiples registros y autenticaciones. El WebAuthn Relying Party usa este valor para buscar credentials asociadas.

Archivos Afectados:

  • src/main/java/com/example/fido2demo/service/WebAuthnService.java: líneas 271-275

3. Discoverable Credentials (Resident Keys)

Problema: Las credenciales marcadas como "Require Resident Key" se guardaban en la base de datos con discoverable=false, impidiendo la autenticación passwordless sin username.

Síntomas:

  • Autenticación sin username fallaba incluso con resident keys registradas
  • Campo discoverable siempre false en la base de datos
  • No se podían listar credenciales discoverable

Causa Raíz: El flag discoverable estaba hardcoded a false:

// INCORRECTO
dbCredential.setDiscoverable(false);  // Siempre false

Solución Implementada:

// CORRECTO - Detecta del PublicKeyCredentialCreationOptions
boolean isDiscoverable = request.getAuthenticatorSelection()
    .map(authSel -> authSel.getResidentKey()
        .map(rk -> rk == ResidentKeyRequirement.REQUIRED)
        .orElse(false))
    .orElse(false);
dbCredential.setDiscoverable(isDiscoverable);

Cómo Funciona la Autenticación Passwordless:

  1. Registro con Resident Key:

    • Usuario marca checkbox "Require Resident Key"
    • Backend configura residentKey: REQUIRED en AuthenticatorSelectionCriteria
    • Credential se almacena en el dispositivo FIDO2
    • Base de datos marca discoverable=true
  2. Autenticación sin Username:

    • Usuario deja campo username vacío
    • Backend NO incluye allowCredentials en la request
    • Navegador/dispositivo presenta todas las resident keys para el dominio
    • Usuario selecciona una credential del dispositivo
    • Backend busca credential por credentialId y valida signature

Archivos Afectados:

  • src/main/java/com/example/fido2demo/service/WebAuthnService.java: líneas 150-156

4. Double JSON.stringify

Problema: El credential JSON se estaba serializando dos veces, causando que el backend recibiera una string JSON dentro de otra string JSON.

Síntomas:

  • Error: "Unexpected data encountered" en el backend
  • JSON con escapes: "{\"id\":\"...\"}"en lugar de {"id":"..."}
  • Fallo al parsear con PublicKeyCredential.parseRegistrationResponseJson()

Causa Raíz:

// INCORRECTO - Double stringify
const credentialData = {
  id: credential.id,
  // ...
}
body: JSON.stringify({
  sessionId,
  credential: JSON.stringify(credentialData)  // Ya dentro de JSON.stringify()
})

Solución Implementada:

// CORRECTO - Single stringify en variable, luego usar como string
const credentialJson = JSON.stringify({
  id: credential.id,
  rawId: arrayBufferToBase64url(credential.rawId),
  type: credential.type,
  response: { /* ... */ }
})

const response = await fetch('/api/webauthn/register/finish', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    sessionId,
    credential: credentialJson  // String, no objeto
  })
})

Archivos Afectados:

  • frontend/src/components/Registration.jsx: líneas 103-124
  • frontend/src/components/Authentication.jsx: líneas 132-155

5. Session ID Mismatch

Problema: El controller generaba un sessionId diferente al que el service almacenaba, causando que las requests de finish fallaran.

Síntomas:

  • Error: "No pending registration/authentication found for session"
  • SessionId enviado por frontend no encontrado en pendingRegistrations/pendingAuthentications

Causa Raíz:

// INCORRECTO - Controller genera su propio sessionId
@PostMapping("/authenticate/begin")
public ResponseEntity<?> beginAuthentication(@RequestBody AuthenticationRequest request) {
    AssertionRequest assertionRequest = webAuthnService.startAuthentication(...);
    String sessionId = generateSessionId();  // Diferente al del service!
    // ...
}

Solución Implementada:

// CORRECTO - Service devuelve el sessionId que generó
public class AuthenticationStartResponse {
    private final AssertionRequest assertionRequest;
    private final String sessionId;  // El mismo que se guarda en pendingAuthentications
    // ...
}

@PostMapping("/authenticate/begin")
public ResponseEntity<?> beginAuthentication(@RequestBody AuthenticationRequest request) {
    AuthenticationStartResponse response = webAuthnService.startAuthentication(...);
    return ResponseEntity.ok(Map.of(
        "publicKey", response.getAssertionRequest().getPublicKeyCredentialRequestOptions(),
        "sessionId", response.getSessionId()  // Usar el del service
    ));
}

Archivos Afectados:

  • src/main/java/com/example/fido2demo/service/WebAuthnService.java: líneas 162-173, 175-199
  • src/main/java/com/example/fido2demo/controller/WebAuthnController.java: líneas 76-97

6. Transports Field Validation

Problema: El campo transports venía como null o tipo incorrecto desde el backend, causando errores de validación en el navegador.

Síntomas:

  • Error: "Failed to read the 'transports' property from 'PublicKeyCredentialDescriptor': The provided value cannot be converted to a sequence"
  • Fallo al llamar navigator.credentials.create() o get()

Solución Implementada:

// Limpiar transports inválidos
allowCredentials: publicKey.allowCredentials?.map(cred => {
  const converted = {
    ...cred,
    id: base64UrlToArrayBuffer(cred.id)
  }
  // Eliminar transports si es null o no es array
  if (!converted.transports || !Array.isArray(converted.transports)) {
    delete converted.transports
  }
  return converted
}) || []

Archivos Afectados:

  • frontend/src/components/Registration.jsx: líneas 184-194
  • frontend/src/components/Authentication.jsx: líneas 65-76

7. Null Extension Values

Problema: El backend devolvía extensiones con valores null, causando que el navegador rechazara la request.

Síntomas:

  • Errores de validación en navigator.credentials.create()
  • Extensions con valores undefined/null

Solución Implementada:

// Limpiar extensions antes de enviar al WebAuthn API
if (convertedPublicKey.extensions) {
  Object.keys(convertedPublicKey.extensions).forEach(key => {
    if (convertedPublicKey.extensions[key] === null ||
        convertedPublicKey.extensions[key] === undefined) {
      delete convertedPublicKey.extensions[key]
    }
  })
  // Eliminar objeto extensions si está vacío
  if (Object.keys(convertedPublicKey.extensions).length === 0) {
    delete convertedPublicKey.extensions
  }
}

Archivos Afectados:

  • frontend/src/components/Registration.jsx: líneas 206-218
  • frontend/src/components/Authentication.jsx: líneas 86-96

Lecciones Aprendidas

  1. Base64url vs Base64: Siempre usar Base64url para datos WebAuthn, nunca Base64 estándar
  2. Consistencia de UserHandle: El userHandle debe ser determinístico basado en el username
  3. Single Source of Truth: Los IDs de sesión deben generarse en un solo lugar (service layer)
  4. Validación de Datos: Limpiar valores null/undefined antes de enviar al WebAuthn API
  5. Resident Keys: El flag discoverable debe detectarse del AuthenticatorSelection original
  6. Serialización JSON: Cuidado con double-stringify al enviar credentials al backend
  7. Logging: Añadir logs detallados ayuda enormemente en debugging de WebAuthn

Testing con Virtual Authenticator

El proyecto funciona perfectamente con Chrome DevTools Virtual Authenticator:

  1. Abrir Chrome DevTools (F12)
  2. Ir a "More tools" → "WebAuthn"
  3. Click en "Enable virtual authenticator environment"
  4. Add authenticator con las opciones deseadas:
    • Protocol: ctap2
    • Transport: usb
    • Supports resident keys: ✓
    • Supports user verification: ✓

Todos los flujos (registro con/sin resident key, autenticación con/sin username) funcionan correctamente.


¡Gracias por usar FIDO2 Demo! 🔐✨

Este sistema de demostración está diseñado para ser una implementación de referencia completa de FIDO2/WebAuthn, proporcionando tanto un ejemplo funcional como una base sólida para implementaciones en producción.

About

FIDO2 Demo to test capabilities of the hardware token

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors