Skip to content
Flag of Europe
Made in the European Union · Independently built · Released under EUPL 1.2

00.51.00

Release date: 2026-05-08 Previous release: 00.50.00 (pre-public) Next release: 00.60.00 Maven coordinates (parent): com.svenruppert:security-for-flow-parent:00.51.00

This release moves the project from a single Vaadin demo of an SPI-based security framework to a small multi-module library with two reference demos — one in-JVM, one REST-authoritative — plus a complete first-run bootstrap mechanism, a central logout flow, and substantially harder test coverage on the three library modules.

There is no breaking API change for consumers that already used AuthenticationService, AuthorizationService, AccessEvaluator, LoginListener and LoginView from 00.50.00. New SPI types are opt-in.

Highlights

  • 5 → 7 Maven modules with strict library / adapter / demo separation
  • New REST adapter (security-rest) for protecting REST handlers with the same annotation model as Vaadin routes
  • Complete first-run bootstrap subsystem (3 modes, atomic POSIX-0600 token files, configurable TTL, fail-fast on DISABLED + no admin)
  • Adapter-neutral decision model (AuthorizationDecision, AccessContext, SecuritySubject) usable from both Vaadin and REST
  • Generic annotations @RequiresRole, @RequiresPermission, @ProtectedBy shipped with built-in evaluators
  • Central LogoutService SPI with Vaadin adapter that handles VaadinSession, HttpSession, and browser-side redirect in the correct order
  • Reusable building blocks extracted from demos: PermissionGuard, StaticRolePermissionMapping, RolePermissionResolver, SecuredOperationRegistry, OperationVisibilityService, BootstrapStatus, BootstrapConfigurationLoader
  • Third demo demo-vaadin-rest-client showing the two-tier picture
  • Mutation coverage lifted across all three library modules (security-core 68 % → 86 %, security-rest 85 % → 97 %, security-vaadin 13 % → 79 %)

Module structure

ModuleArtifactPurpose
security-coresecurity-coreGeneric, framework-neutral security concepts and decision logic
security-vaadinsecurity-vaadinVaadin Flow adapter (navigation, listener, session, logout)
security-restsecurity-restFramework-light REST adapter (no Spring, no Jakarta Security)
demo-rest-shareddemo-rest-sharedTiny module — DemoEndpoints + DemoJson for the REST demos
demo-vaadindemo-vaadinSingle-JVM Vaadin reference (WAR)
demo-restdemo-restREST reference (JAR) — JDK HttpServer, no Spring
demo-vaadin-rest-clientdemo-vaadin-rest-clientTwo-tier reference: Vaadin UI consumes a separate REST backend

Strict dependency rules:

security-core            -> (no project deps)
security-vaadin          -> security-core
security-rest            -> security-core
demo-vaadin              -> security-core, security-vaadin
demo-rest                -> security-core, security-rest, demo-rest-shared
demo-vaadin-rest-client  -> security-core, security-vaadin, demo-rest-shared

First-run bootstrap

A fresh installation now does not ship with a hard-coded admin.

ModeWhere the token livesSurvives restart?
DISABLEDn/an/a (fail-fast on startup if no admin exists)
TRANSIENT_CONSOLEIn-memory only, printed to server consoleNo
PERSISTENT_FILEFile on disk (POSIX 0600, atomic creation)Yes

Configuration via system property → environment variable → default:

System propertyEnvironment variableDefault
security.bootstrap.modeSECURITY_BOOTSTRAP_MODETRANSIENT_CONSOLE
security.bootstrap.token.fileSECURITY_BOOTSTRAP_TOKEN_FILE./data/bootstrap.token
security.bootstrap.token.ttlSECURITY_BOOTSTRAP_TOKEN_TTLPT24H (ISO-8601)

Three setup paths:

  • RESTGET /api/bootstrap/status, POST /api/bootstrap/admin
  • CLIinit-admin command, password via Console.readPassword()
  • Vaadin /setup route — both single-JVM and REST-authoritative variants are demonstrated

Tokens are XXXX-XXXX-XXXX-XXXX-XXXX, ~100 bits, ambiguity-free alphabet via SecureRandom; BootstrapToken.matches(...) is constant-time; file-mode tokens are created atomically (POSIX rw-------, no umask window); token values never reach the logger, HTTP body, or Vaadin notification. Bootstrap admin creation is serialised under a single ReentrantLock — verified by a 16-thread parallelism test. See Bootstrap.

Central LogoutService

LogoutService SPI in security-core, Vaadin adapter in security-vaadin. LogoutPolicy lets the application choose:

Policy factorySubject clearedVaadin session closedHTTP session invalidated
LogoutPolicy.clearSubjectOnly(target)
LogoutPolicy.invalidateHttpSession(target)
LogoutPolicy.fullInvalidate(target)

The Vaadin adapter calls Page.setLocation(...) for the redirect before invalidating the session, so the response carries the redirect to the browser.

The 00.51 LogoutContext + LogoutPolicy shape was replaced in 00.60 with the sharper logout(SubjectId, LogoutScope) signature. See the 00.60 migration guide.

New demo: demo-vaadin-rest-client

A second Vaadin demo that consumes demo-rest over HTTP instead of running everything in one JVM.

  • WAR running on Jetty port 9090 (parallel to demo-rest on 8080)
  • All HTTP / JSON / endpoint paths confined to one backend/ package — verified with a single grep
  • BackendException with semantic Kind (Unauthenticated / Forbidden / NotFound / BadRequest / Conflict / ServerError / Transport)
  • Sealed LoginResult and BootstrapResult so views switch instead of try/catch
  • REST-authoritative /setup flow — the Vaadin process never runs a local InitialAdminBootstrapService; it posts to the backend
  • Three view-protection styles demonstrated side by side:
    • @RequiresPermission("document:read") (Style A1)
    • @RequiresRole("ROLE_ADMIN") (Style A2)
    • @VisibleForRoles({ADMIN, EDITOR}) — project-specific custom annotation backed by ProjectRoleAccessEvaluator (Style B)
  • 13-case integration test against an in-process DemoRestServer
  • New shared module demo-rest-shared carries DemoEndpoints + DemoJson for both the demo server and any client

Bug fixes

  • VaadinAccessContextFactory now populates AccessContext.subject(). In 00.50.00 the compatibility constructor for the Vaadin path always produced subject = Optional.empty(), so generic @RequiresRole / @RequiresPermission evaluators always saw “no subject” and returned Unauthenticated — causing a login loop after successful authentication.
  • AccessContext.vaadinAttributes no longer rejects the empty path. Navigation to the Vaadin root "" previously crashed because of an over-zealous requireNotBlank on path. Replaced with requireNonNull + regression test (AccessContextTest).
  • InitialAdminBootstrapService cleanup-failure is now visible. When deleting the persistent token file fails after a successful setup, the service emits a WARNING via java.util.logging (without the token value).

Mutation coverage

ModuleKilled mutantsLine coverage (mutated classes)Test strength
security-core200 → 254 of 294 (68 % → 86 %)81 % → 85 %83 % → 95 %
security-rest33 → 38 of 39 (85 % → 97 %)88 % → 93 %92 % → 97 %
security-vaadin16 → 94 of 119 (13 % → 79 %)13 % → 73 %89 % → 95 %

Tests run against the original implementation, not against mocks — that’s the project-wide testing policy from this release forward.

mvn -pl :security-core   org.pitest:pitest-maven:mutationCoverage -Dpitest-test-classes='com.svenruppert.*'
mvn -pl :security-rest   org.pitest:pitest-maven:mutationCoverage -Dpitest-test-classes='com.svenruppert.*'
mvn -pl :security-vaadin org.pitest:pitest-maven:mutationCoverage -Dpitest-test-classes='com.svenruppert.*'

The pitest-test-classes override is required — the parent-pom default junit.com.svenruppert.* does not match this project’s test package layout.

Known limitations (closed in 00.60.00)

The following items from Konzept-V00.60.00.md were not yet implemented in 00.51.00 but all shipped in 00.60.00:

  • SecurityAuditService (Login / Logout / AccessDenied / ActionDenied events)
  • LoginAttemptPolicy (brute-force throttling)
  • minimal SessionPolicy (idle timeout, absolute lifetime, rotation after login)
  • PasswordHasher.needsRehash(...) + re-hash on login
  • ActionAuthorizationService as injectable SPI
  • Karibu / TestBench-based UI tests (00.60 ships Vaadin Browserless tests instead)
  • SecurityServiceResolver extensions for the new SPIs

Build

  • Java 26
  • Maven 3.9.9+
  • Vaadin 25.1.1
  • Jetty 12.1.8 (EE11)
mvn clean install