Commit a5e15bb
fix: resolve security and correctness findings from review (M1–M9)
Address the actionable High/Medium/Low findings from the multi-agent
review. All fixes land together; `./gradlew check` is green (spotless +
tests incl. Testcontainers + JaCoCo).
High
- magic-link(jwt): stop magic links inheriting the 1h access-token TTL.
PkAuthJwtIssuer gains an issue(claims, ttlOverride) overload; MagicLink
now issues with its own tokenTtl (default 15m) and enforces
consumedJtiTtl >= tokenTtl at construction, closing the replay window
where a redeemed link stayed valid after its single-use JTI was evicted.
- magic-link: startLogin now delivers ONLY to the address bound to the
resolved user (UserLookup#emailFor), never the caller-supplied one —
previously an attacker could request a login token for any account by
username and have it sent to an address they control. Skips the send
(enumeration-resistant Sent) when no bound email exists.
- build: reconcile the Spotless version/pin/docs divergence — the catalog
comment + dependabot ignore claimed a 7.x pin while the build ran 8.7.0
(the ignore targeted the plugin-marker artifact, not the implementation
artifact, so it never matched). Docs now match reality; dead ignore removed.
Medium
- core: enforce per-request userVerification at finish. The resolved UV is
persisted on ChallengeRecord at start and the finish step now requires UV
if EITHER the global config OR the per-request value is REQUIRED (max of
the two), so a step-up REQUIRED can no longer be silently downgraded.
Adds challenges.user_verification (Flyway V11, schema -> "11") and carries
it through the JDBI and DynamoDB challenge stores.
- dynamodb(refresh): make create() a single atomic TransactWriteItems for
the primary + user/family index items, eliminating the orphaned-primary
window that revokeFamily/revokeAllForUser would silently skip; duplicate
refreshId now surfaces via PkAuthPersistenceException, not a raw escape.
- jdbi(credentials): updateSignCount guard relaxed from `< :sc` to `<= :sc`
so last_used_at is recorded for sync passkeys that always report
signCount=0 (regression is still rejected), per the SPI contract.
- spring: pin pkAuthSecurityFilterChain order so a host catch-all chain
can't swallow /auth/**, and disable global servlet auto-registration of
the JWT filter so it runs only inside the security chain.
Low
- core: null-guard AAGUID in persistRegistration so a null AAGUID returns a
sealed RegistrationResult instead of NPE-ing across the boundary.
- jwt: JwtKeyset.es256 stores only public JWKs in verificationSource() so a
host that publishes it as JWKS cannot leak the private signing key.
- otp: TwilioSmsSender no longer echoes accountSid/fromNumber/authToken into
its exception message.
Deferred (noted for follow-up): magic-link dedicated-audience split (needs
per-adapter validator rewiring) and in-store OTP expiry filtering (needs a
ClockProvider threaded through the OtpRepository SPI).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent e2a3a77 commit a5e15bb
21 files changed
Lines changed: 447 additions & 83 deletions
File tree
- .github
- gradle
- pk-auth-core/src
- main/java/com/codeheadsystems/pkauth
- internal
- spi
- test/java/com/codeheadsystems/pkauth/spi
- pk-auth-jwt/src/main/java/com/codeheadsystems/pkauth/jwt
- pk-auth-magic-link/src
- main/java/com/codeheadsystems/pkauth/magiclink
- test/java/com/codeheadsystems/pkauth/magiclink
- pk-auth-otp/src/main/java/com/codeheadsystems/pkauth/otp
- pk-auth-persistence-dynamodb/src/main/java/com/codeheadsystems/pkauth/persistence/dynamodb
- pk-auth-persistence-jdbi/src/main
- java/com/codeheadsystems/pkauth/persistence/jdbi
- resources/db/migration
- pk-auth-spring-boot-starter/src
- main/java/com/codeheadsystems/pkauth/spring/autoconfigure
- test/java/com/codeheadsystems/pkauth/spring/autoconfigure
- pk-auth-testkit/src/main/java/com/codeheadsystems/pkauth/testkit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | 20 | | |
27 | 21 | | |
28 | 22 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
14 | | - | |
15 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
16 | 18 | | |
17 | 19 | | |
18 | 20 | | |
| |||
Lines changed: 41 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
229 | 229 | | |
230 | 230 | | |
231 | 231 | | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
232 | 239 | | |
233 | 240 | | |
234 | 241 | | |
235 | 242 | | |
236 | 243 | | |
237 | 244 | | |
| 245 | + | |
238 | 246 | | |
239 | 247 | | |
240 | 248 | | |
| |||
244 | 252 | | |
245 | 253 | | |
246 | 254 | | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | 255 | | |
251 | 256 | | |
252 | 257 | | |
| |||
351 | 356 | | |
352 | 357 | | |
353 | 358 | | |
354 | | - | |
| 359 | + | |
355 | 360 | | |
356 | 361 | | |
357 | 362 | | |
358 | 363 | | |
359 | 364 | | |
360 | 365 | | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
361 | 384 | | |
362 | 385 | | |
363 | 386 | | |
| |||
399 | 422 | | |
400 | 423 | | |
401 | 424 | | |
402 | | - | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
403 | 432 | | |
404 | 433 | | |
405 | 434 | | |
| |||
480 | 509 | | |
481 | 510 | | |
482 | 511 | | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
483 | 517 | | |
484 | 518 | | |
485 | 519 | | |
486 | 520 | | |
487 | 521 | | |
488 | 522 | | |
| 523 | + | |
489 | 524 | | |
490 | 525 | | |
491 | 526 | | |
492 | | - | |
493 | | - | |
494 | | - | |
495 | 527 | | |
496 | 528 | | |
497 | 529 | | |
| |||
648 | 680 | | |
649 | 681 | | |
650 | 682 | | |
651 | | - | |
| 683 | + | |
652 | 684 | | |
653 | 685 | | |
654 | 686 | | |
| |||
Lines changed: 26 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
17 | 24 | | |
18 | 25 | | |
19 | 26 | | |
20 | 27 | | |
21 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
22 | 33 | | |
23 | 34 | | |
24 | 35 | | |
| |||
30 | 41 | | |
31 | 42 | | |
32 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
33 | 55 | | |
34 | 56 | | |
35 | 57 | | |
| |||
41 | 63 | | |
42 | 64 | | |
43 | 65 | | |
| 66 | + | |
44 | 67 | | |
45 | 68 | | |
46 | 69 | | |
47 | 70 | | |
48 | 71 | | |
49 | | - | |
| 72 | + | |
| 73 | + | |
50 | 74 | | |
51 | 75 | | |
52 | 76 | | |
| |||
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
27 | 51 | | |
28 | 52 | | |
29 | 53 | | |
| |||
Lines changed: 5 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
67 | | - | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
68 | 71 | | |
69 | 72 | | |
70 | | - | |
| 73 | + | |
71 | 74 | | |
72 | 75 | | |
73 | 76 | | |
| |||
Lines changed: 22 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| 18 | + | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
| |||
78 | 80 | | |
79 | 81 | | |
80 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
81 | 101 | | |
82 | 102 | | |
83 | 103 | | |
84 | 104 | | |
85 | | - | |
| 105 | + | |
| 106 | + | |
86 | 107 | | |
87 | 108 | | |
88 | 109 | | |
| |||
0 commit comments