feat!: rebuild Ogiri 0.1.0 for Spring Boot, PostgreSQL, MySQL and optional caching - #60
feat!: rebuild Ogiri 0.1.0 for Spring Boot, PostgreSQL, MySQL and optional caching#60mosobande wants to merge 13 commits into
Conversation
Cache assessment: do not add cross-request authentication caching to 0.1.0Reviewed candidate: Decision: caching has not earned a production dependency, configuration option or durable test suite. No cache implementation was added. This is a decision under current evidence, not a claim that no adopter will ever benefit from caching. Evidence inspected
Recovered the two original benchmark JSON files from artifact
Boundary: Java 17, local PostgreSQL/MySQL containers, 10,000 inserted sessions, 1,000 warmup calls, eight pooled connections, repeated lookup of ONE token. These are short warm-path storage measurements, excluding account directory, HTTP, realistic session cardinality/access distribution, remote-database latency and concurrent revocation workload. They do not establish sustained production capacity or a cache/no-cache speedup. There is no supplied production latency budget or demonstrated production session-query bottleneck that makes caching necessary. Why a generic Spring cache is not the answerA positive session cache can accept a revoked token until invalidation/expiry. Caching the complete principal also delays account disablement and permission changes. An illustrative cache-aside race: reader obtains a live SQL row; revoker commits and evicts; reader installs its old result after eviction. A TTL bounds some exposure but does not preserve immediate revocation, and expiry must not be extended by cache hits. An authoritative version check on every hit preserves freshness by retaining the shared-store read we were trying to remove. Spring's Cache/CacheManager abstraction is appropriate when caching is justified, but does not itself solve multi-process propagation or concurrent load/eviction: Spring cache strategies. A local cache plus Redis Pub/Sub is not reliable revocation delivery: Redis documents at-most-once delivery. The same performance-versus-revocation trade-off is described in RFC 7662 section 4; this is an applicable design consideration, not a claim that Ogiri implements the remote RFC endpoint. Scope decisions
Reopen only when representative measurements show session/account lookup violating the consumer's latency or database-capacity budget and a cached variant materially improves it. Before shipping that variant, establish the allowed revocation/role-change staleness and prove expiry, concurrent fill-after-revoke, revoke-all, cross-node invalidation and outage behaviour. Reuse Spring Cache/CacheManager rather than inventing a cache framework; provider requirements and security semantics must be explicit. QP guidance applied: ro-wo (necessity is unproved), architect/module-design (ownership and consistency), pare (no speculative mechanism or tests), technical-writing/yo-slop (decision and evidence boundaries). Library source, dependencies, public API and version remain unchanged. The temporary artifact-readback workflow was removed after inspection. |
Purpose and current scope
Rebuild the unpublished library at 0.1.0 for low-setup Spring Boot 4.1 / Java 17+ integration. This is a new API and schema lineage, not a compatible v3/v4 downgrade. It supersedes the earlier PostgreSQL-only candidate in this PR and remains an alternative to #59, not a stack on it. No merge, release tag or Maven Central publication has occurred.
Verified head:
5119a06f42fab49ed1b29fd38ddcebe33edad608, based onoriatd3240a405722689e608873a65c419ef0c3658739.What ships
Two code artifacts and one parent POM:
com.quantipixels.ogiri:ogiri:0.1.0: Java session lifecycle using Spring JDBC and Spring transaction management, supporting PostgreSQL and MySQL. No JPA entity hierarchy, custom storage framework, required cache provider or Kotlin runtime.com.quantipixels.ogiri:ogiri-spring-boot-starter:0.1.0: conditional Boot configuration, validated properties/IDE metadata, Spring's native opaque-bearer pipeline, reusable security-chain integration and optional JSON session endpoints.The default consumer supplies its existing
UserDetailsService, ordinaryspring.datasource.*settings, one database driver and application-owned schema migrations. Spring'sAuthenticationConfigurationreuses application authentication providers/manager and password encoding.OgiriAccountshandles stable IDs, mutable login names and tenant-aware identity when the default immutable-username mapping is unsuitable.Built-in endpoints cover sign-in, current session, session listing, owned-session revocation, sign-out and revoke-all. The default security chain exists only when the application has no chain. Existing/multiple chains use
OgiriSecuritywithout losing application authorization or other authentication methods. Endpoints and the whole starter can be disabled independently. Duplicate Authorization-header rejection and JSON-login CSRF handling are packaged rather than copied from the example. Account registration, recovery, MFA and OAuth/OIDC federation are not reimplemented.Database and security behavior
Both engines use the same lifecycle and contract tests; database-specific time expressions, lock-row insertion and DDL stay internal. Packaged PostgreSQL/MySQL templates use
ogiri_sessionsplus stable digest-keyedogiri_subject_locks. MySQL requires InnoDB. Identity comparisons preserve the complete(realm, tenantId, stableSubjectId)without case-folding or padding ambiguity. Ogiri never runs DDL at startup or reserves an application Flyway version.Credentials contain 256 random bits; only SHA-256 digests are stored. Fixed expiry and session limits remain configurable; admission rejects rather than silently evicting another device. Default authentication performs one indexed session read and no writes, then resolves current account status and authorities. Spring manages independent mutation commits and JDBC/JPA transaction suspension for authoritative database reads. An outer transaction holding a connection needs spare pool capacity; ordinary use is exercised with one pooled connection.
Optional cache support, disabled by default
Developers can opt into session caching through their existing Spring
CacheManagerand a dedicated region:The default age when enabled is five seconds; accepted values are 1ms through 1m. Every hit checks its original validation age and absolute session expiry. Hits and late concurrent fills do not restart that age. Keys contain token digests; values contain serializable session metadata. Ogiri does not cache plaintext tokens, passwords, account status, authorities, principals, misses or failed database lookups. Account checks still run on each request, with freshness determined by the application's account adapter.
The application chooses the provider and eviction/size/serialization policy. Caffeine with Boot auto-configuration and Spring's store-by-value concurrent-map provider are exercised; a particular Redis deployment/custom serializer is not thereby certified. Enabling the feature without a cache manager or named region fails startup. A custom
JdbcSessionsbean takes precedence. No provider is added to the default runtime, and Ogiri does not globally enable application caching or disable credential erasure.Opt-in changes consistency: successful revoke/revoke-all evicts after the independent SQL commit, but eviction is best effort. Other JVMs' local caches, concurrent refills, direct SQL changes and provider failures can retain validation until its original age/expiry deadline. Bounds assume synchronized clocks and trusted cache storage. A valid cache hit can survive a database outage for the remaining window if account checks succeed. Cache read failures fall back to SQL; cache eviction failure cannot undo a committed revocation. Leave caching disabled for strict per-request session freshness. README and SECURITY.md include the integration recipe and these limitations.
Verified results at the current head
The final PR build passed all four combinations: Java 17 and 25 × PostgreSQL 16 and MySQL 8.4. CodeQL analysis completed successfully for the same head. These are current-head results, not checks borrowed from the earlier PostgreSQL-only candidate.
All four downloaded build artifacts matched GitHub's SHA-256 digests. Their verification records each contain 36 executed test invocations, zero failures, errors or skips:
Counts include parameter variants and reuse of the same HTTP contract with caching on/off. The matrix therefore executes 144 invocations, not 144 unique scenarios. Tests observe real database/HTTP behavior and deterministic cache boundaries rather than mock call choreography.
The same final build also verified:
results: []; this is no known findings in those scanned graphs at the run, not universal vulnerability clearance or a scan of every optional provider/test dependency.Before delivery, source verification tested both engines on Java 17 and non-force-pushed coherent native source commits. Its source head was
69f81e9afb652492c6f0ef6edece350b855dcb89; the final head adds the packaged cache-metadata gate. An initial serialization test exposed a missing standalone Spring class-loader callback; the fixture was corrected without weakening the value-copy assertion. The temporary cache-verification workflow has been removed from the execution branch.Publication and limits
Maven publication preparation includes the parent/core/starter POMs, six binary/source/Javadoc JARs, an opt-in signing profile, and the verified local deployment/bundle rehearsal. Actual signing credentials, namespace ownership, Central acceptance and public publication remain publisher-controlled gates. The tested consumer pins Tomcat 11.0.25; host applications retain dependency-management ownership.
The opt-in storage benchmark harness remains available. Earlier local no-cache measurements exclude HTTP and account lookup; no cache speedup or production throughput guarantee is claimed. No automatic refresh/rotation, cookie transport, reactive adapter, independent human security clearance or universal JDBC portability is claimed.
Earlier session HTML and PostgreSQL-only descriptions are historical snapshots, not the current handoff. The earlier no-cache assessment still explains the uncached default; this revision adds the subsequently requested opt-in capability.