|
| 1 | +## [4.2.0] - 2026-02-21 |
| 2 | +### Features |
| 3 | +- WebAuthn/Passkeys (opt-in, disabled by default) |
| 4 | + - End-to-end passwordless authentication using Spring Security 7 WebAuthn and WebAuthn4J: |
| 5 | + - Supports platform authenticators (Touch ID, Face ID, Windows Hello) and roaming keys (YubiKey), including synced passkeys (iCloud Keychain, Google Password Manager). |
| 6 | + - New WebAuthnAuthenticationSuccessHandler converts the WebAuthn principal to your DSUserDetails and issues a WebAuthnAuthenticationToken, allowing downstream code and audit logic to distinguish passkey vs password sessions without behavior changes elsewhere. |
| 7 | + - Passkey Management REST API (auth required) under /user/webauthn: |
| 8 | + - GET /user/webauthn/credentials — List user’s passkeys (returns DTO with id, label, created, lastUsed, transports as List<String>, backup flags). |
| 9 | + - GET /user/webauthn/has-credentials — Boolean check for any registered passkeys. |
| 10 | + - PUT /user/webauthn/credentials/{id}/label — Rename a passkey (label trimmed and limited to 64 chars). |
| 11 | + - DELETE /user/webauthn/credentials/{id} — Delete a passkey with “last-credential” protection to avoid lockouts if the user has no password. |
| 12 | + - WebAuthn persistence and repositories: |
| 13 | + - JPA entities: WebAuthnUserEntity and WebAuthnCredential. |
| 14 | + - Spring Data repositories and a repository bridge that implements PublicKeyCredentialUserEntityRepository so Spring Security uses your application users. |
| 15 | + - Query repository provides DTO projections, ownership checks, a JOIN FETCH findByIdWithUser to avoid N+1s, and a lock-and-count operation for safe deletions. |
| 16 | + - Configuration and conditional loading: |
| 17 | + - New user.webauthn.* configuration (enabled, rpId, rpName, allowedOrigins) with sane defaults for localhost. |
| 18 | + - All WebAuthn beans, endpoints, and exception advice are @ConditionalOnProperty(name="user.webauthn.enabled") so they only register when explicitly enabled. |
| 19 | + - Security config updated to use WebAuthnConfigProperties; you must add /webauthn/authenticate/** and /login/webauthn to unprotected URIs. |
| 20 | + - Database schema: |
| 21 | + - Tables user_entities and user_credentials (ON DELETE CASCADE on FKs for cleanup safety). |
| 22 | + - Label column length reduced from 255 to 64 to avoid UI overflow in consuming apps. |
| 23 | + - Account cleanup: |
| 24 | + - WebAuthnPreDeleteEventListener listens for UserPreDeleteEvent and deletes the user’s WebAuthn entity and all credentials (also enforced at DB level via cascade). |
| 25 | + - Safer identifiers and metadata: |
| 26 | + - User handle generated from SecureRandom bytes (privacy-preserving, non-derivable from user ID). |
| 27 | + - Transports parsed safely and exposed as a List<String> in responses. |
| 28 | + |
| 29 | +- Persistence architecture improvements |
| 30 | + - Migrated WebAuthn persistence from ad-hoc JDBC/SQL to JPA entities and Spring Data repositories: |
| 31 | + - Eliminates raw SQL and the BLOB/VARCHAR mismatch for credential_id. |
| 32 | + - Lets Hibernate manage schema (ddl-auto) when desired; kept reference schema scripts for manual DBs. |
| 33 | + - Bulk delete for credentials by user entity to avoid N+1 delete operations. |
| 34 | + |
| 35 | +### Fixes |
| 36 | +- Safety, validation, and API quality |
| 37 | + - Added @Validated and path variable constraints (@NotBlank and @Size(max=512)) to management endpoints; centralized error mapping via WebAuthnManagementAPIAdvice. |
| 38 | + - Trim passkey labels before length validation and storage; default label to “Passkey” when missing. |
| 39 | + - Safe parsing of AuthenticatorTransport and PublicKeyCredentialType with WARN logs for unknown values (prevents IllegalArgumentException on unexpected inputs). |
| 40 | + - Management advice logs expected business/validation errors without noisy stack traces. |
| 41 | + |
| 42 | +- Concurrency and data integrity |
| 43 | + - Fixed TOCTOU race in last-credential protection: introduced transactional lock-and-count with pessimistic locking and Propagation.MANDATORY so counts and deletes execute within one transaction boundary. |
| 44 | + - Prevent orphaned WebAuthn user entities: nullable=false on user join, explicit IllegalStateException if an entity cannot be linked to an application user. |
| 45 | + - Eliminated N+1 queries when verifying credential ownership via a JOIN FETCH repository method. |
| 46 | + - Replaced iterative credential deletion with single-statement bulk delete (@Modifying @Query) in deleteByUserEntity(). |
| 47 | + - Added ON DELETE CASCADE to WebAuthn FKs for database-level cleanup when users/entities are removed. |
| 48 | + |
| 49 | +- Build/test stability and noise reduction |
| 50 | + - FileAuditLogQueryServiceTest: fixed temp directory handling and later removed a global system property hack to keep tests parallel-safe; switched to ISO timestamp parsing for consistent sort assertions. |
| 51 | + - Test output made context-aware: gradle build is quiet (short exception format), gradle test is verbose (full stack traces); added JVM args and a test logback to remove spurious warnings. |
| 52 | + |
| 53 | +### Breaking Changes |
| 54 | +- None. WebAuthn is entirely opt-in and disabled by default. Existing APIs, behavior, and defaults are unchanged for consumers who do not enable the feature. |
| 55 | + |
| 56 | +### Refactoring |
| 57 | +- Centralized WebAuthn error handling with a dedicated @RestControllerAdvice. |
| 58 | +- Introduced WebAuthnConfigProperties and migrated WebSecurityConfig to use properties over scattered @Value fields. |
| 59 | +- Extracted WebAuthnTransportUtils for shared, safe parsing of transport strings; returns unmodifiable collections and throws on construction to enforce utility usage. |
| 60 | +- Consolidated persistence through JPA (entities + repositories + bridge) and removed raw SQL-based schema code. |
| 61 | +- WebAuthnAuthenticationSuccessHandler now issues a dedicated WebAuthnAuthenticationToken instead of a generic UsernamePasswordAuthenticationToken. |
| 62 | + |
| 63 | +### Documentation |
| 64 | +- README and CONFIG updated with: |
| 65 | + - WebAuthn setup, endpoints, and requirements. |
| 66 | + - Dev and prod configuration examples, HTTPS requirements, and unprotected URI notes. |
| 67 | + - Notes on automatic cleanup and disabled-by-default behavior. |
| 68 | +- CHANGELOG.md updated for 4.2.0 with a comprehensive WebAuthn entry. |
| 69 | +- CLAUDE.md expanded with testing infrastructure, startup order, auto-configuration details, and library design invariants (compileOnly starters, serializable isolation, event-driven design). |
| 70 | +- README dependency snippets updated to version 4.2.0. |
| 71 | + |
| 72 | +### Testing |
| 73 | +- New and updated test suites covering: |
| 74 | + - WebAuthnFeatureDisabledIntegrationTest and WebAuthnFeatureEnabledIntegrationTest (bean/endpoint presence, validation and business error responses). |
| 75 | + - WebAuthnManagementAPITest (endpoint behavior, validation, exception mapping). |
| 76 | + - WebAuthnCredentialManagementServiceTest (rename/delete flows, trim-before-store, TOCTOU protection). |
| 77 | + - WebAuthnAuthenticationSuccessHandlerTest (principal conversion and token type). |
| 78 | + - WebAuthnUserEntityBridgeTest (entity lookup/creation, SecureRandom handle generation, concurrent creation scenario). |
| 79 | + - WebAuthnPreDeleteEventListenerTest (bulk credential deletion + entity cleanup). |
| 80 | + - WebAuthnTransportUtilsTest (null/empty, whitespace trimming, multiple values, unmodifiable collections). |
| 81 | +- Test logging tuned to reduce noise; added logback-test.xml and JVM args to suppress irrelevant warnings. |
| 82 | + |
| 83 | +### Other Changes |
| 84 | +- Build and dependencies: |
| 85 | + - Added Spring Security WebAuthn (compileOnly) and WebAuthn4J core. |
| 86 | + - Added test dependency on spring-security-webauthn. |
| 87 | + - Removed a stale commented version line from build.gradle. |
| 88 | +- Defaults: |
| 89 | + - WebAuthn disabled by default via dsspringuserconfig.properties; added default allowedOrigins for localhost. |
| 90 | +- Versioning: |
| 91 | + - Intermediate bump to 4.1.1-SNAPSHOT (release plugin), followed by 4.2.0-SNAPSHOT for the WebAuthn feature. |
| 92 | +- Cleanup: |
| 93 | + - Removed PASSKEY.md planning document. |
| 94 | + - Reduced label length for passkeys to 64 characters to prevent UI layout issues in consuming apps. |
| 95 | + |
1 | 96 | ## [4.2.0] - 2026-02-21 |
2 | 97 | ### Features |
3 | 98 | - WebAuthn / Passkey support (opt-in, disabled by default) |
|
0 commit comments