Commit Graph

640 Commits

Author SHA1 Message Date
hsiegeln
bc32d7e994 fix: use license/usage endpoint for agent/env/app counts
Some checks failed
CI / docker (push) Has been cancelled
CI / build (push) Has been cancelled
Server moved GET /agents to /environments/{envSlug}/agents and removed
GET /admin/apps. Replace three broken individual calls with a single
GET /admin/license/usage call that returns all counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 12:58:35 +02:00
hsiegeln
c43d7f639f harden: swap cameleer-saas runtime stage to Chainguard JRE
Some checks failed
CI / build (push) Successful in 3m22s
CI / docker (push) Failing after 9s
Replace eclipse-temurin:21-jre-alpine with cgr.dev/chainguard/jre:openjdk-21
for the SaaS management plane image. Use Chainguard's built-in nonroot user
instead of custom adduser. Build stages unchanged (ephemeral).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 09:42:38 +02:00
hsiegeln
5f210b76a9 harden: swap runtime base to Chainguard JRE, remove dead ENTRYPOINT
Replace eclipse-temurin:21-jre-alpine (musl) with cgr.dev/chainguard/jre:openjdk-21
(Wolfi/glibc, daily CVE refresh, signed images + SBOM). Remove the dead ENTRYPOINT
block — DeploymentExecutor overrides it at container creation anyway.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 09:32:49 +02:00
hsiegeln
06134d6e67 fix: TOTP label includes org name, passkeys show device as default name
Some checks failed
CI / build (push) Successful in 2m10s
CI / docker (push) Successful in 1m27s
SonarQube Analysis / sonarqube (push) Failing after 2m57s
- TOTP otpauth URI issuer changed from "Cameleer" to "Cameleer - <org>"
  so authenticator apps display the organization name
- Passkeys without a custom name now show parsed device info (e.g.
  "Chrome on Windows") instead of "Unnamed passkey"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 22:53:05 +02:00
hsiegeln
7fe9c581b0 fix: remove MFA card from tenant settings, constrain card widths
All checks were successful
CI / build (push) Successful in 2m10s
CI / docker (push) Successful in 1m25s
MFA enrollment now happens during sign-in. Tenant settings page reduced
to: Tenant Details + Auth Policy side-by-side (max 520px each), Passkeys
full-width below.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 22:45:31 +02:00
hsiegeln
7fc8a4d407 fix: team invite role resolution, user cleanup, and settings page redesign
All checks were successful
CI / build (push) Successful in 2m9s
CI / docker (push) Successful in 1m33s
- Resolve org role names to Logto role IDs in invite and role change flows
  (fixes entity.relation_foreign_key_not_found on invite)
- Handle existing Logto users on re-invite instead of failing with
  email_already_in_use
- Delete users from Logto when removed from last org membership
- Consolidate tenant settings page into 3 cards: Tenant Details, MFA,
  Authentication Policy — remove duplicate MFA Enforcement and Change
  Password (now in Account Settings)
- Make passkey list scrollable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 22:36:21 +02:00
hsiegeln
e21a9d6046 fix: override WebAuthn type in authentication verify too
All checks were successful
CI / build (push) Successful in 1m57s
CI / docker (push) Successful in 1m30s
Same fix as registration verify — @simplewebauthn/browser returns
type: "public-key" but Logto expects type: "WebAuthn".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 20:57:37 +02:00
hsiegeln
0481cefaf4 fix: sign-in MFA flow overhaul — passkey verify, backup codes, defaults
All checks were successful
CI / build (push) Successful in 2m19s
CI / docker (push) Successful in 1m4s
Four fixes for the MFA sign-in flow:

1. Fix passkey verify crash: extract authenticationOptions from Logto
   response (was passing full response as optionsJSON). Pass
   verificationId to the verify endpoint.

2. Default to passkey verification when no MFA method preference is
   stored (was showing method picker which offered TOTP to passkey-only
   users).

3. Show backup codes after MFA enrollment: new mfaEnrollBackupCodes
   mode with copy/download buttons and confirmation checkbox. Users
   must save codes before completing sign-in.

4. Remove duplicate error alerts in enrollment screens (top-level
   alert handles all modes).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 20:49:32 +02:00
hsiegeln
040ae60be5 fix: correct Experience API endpoints for TOTP and backup codes
All checks were successful
CI / build (push) Successful in 2m4s
CI / docker (push) Successful in 1m1s
- TOTP secret: /verification/totp/secret (not /verification/totp)
- Backup codes: generate via /verification/backup-code/generate first,
  then bind with the returned verificationId. Cannot bind BackupCode
  without generating codes first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:30:54 +02:00
hsiegeln
d8f7452ab7 feat: full MFA enrollment during sign-in — passkey + TOTP + backup codes
All checks were successful
CI / build (push) Successful in 2m2s
CI / docker (push) Successful in 1m10s
- Bind BackupCode after primary MFA factor (WebAuthn or TOTP) to satisfy
  Logto's requirement that backup codes accompany any MFA method.
- Add TOTP enrollment option alongside passkey on the enrollment screen:
  "Use passkey" / "Use authenticator app" / "Set up later".
- TOTP enrollment shows QR code + secret + 6-digit verification inline
  in the sign-in UI, using Experience API endpoints.
- Added createTotpSecret() and verifyTotpSetup() to experience-api.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:22:53 +02:00
hsiegeln
c4fe16048c fix: include WebAuthn in bootstrap MFA factors
All checks were successful
CI / build (push) Successful in 2m14s
CI / docker (push) Successful in 25s
Bootstrap only set [Totp, BackupCode] — WebAuthn was missing. Now
matches LogtoStartupConfig: all three factors available from first boot.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:04:47 +02:00
hsiegeln
cba420fbeb fix: always offer MFA+passkey enrollment, separate availability from enforcement
All checks were successful
CI / build (push) Successful in 2m19s
CI / docker (push) Successful in 1m43s
Two fundamental fixes:

- user.missing_mfa now triggers MfaEnrollmentError (enroll UI) instead
  of MfaRequiredError (verify UI). Users without MFA were shown a TOTP
  code prompt they couldn't fill.
- Logto MFA factors always set to [Totp, WebAuthn, BackupCode] with
  UserControlled policy on startup. Availability is always-on for all
  users. The vendor auth policy controls enforcement (via
  MfaEnforcementFilter), not what Logto offers during sign-in.
- Removed syncMfaConfigToLogto from VendorAuthPolicyController — vendor
  policy changes no longer modify Logto's sign-in experience.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:59:21 +02:00
hsiegeln
67ec409383 fix: null display name, settings scrollbar, redundant passkey offer
All checks were successful
CI / build (push) Successful in 2m20s
CI / docker (push) Successful in 1m36s
- Profile API returns empty string instead of "null" when Logto user
  has no display name set (String.valueOf(null) → "null" bug).
- SettingsPage: add overflowY auto + flex 1 so content scrolls within
  the AppShell layout (which uses overflow: hidden).
- Remove redundant passkey offer from onboarding page — passkey
  enrollment now happens during sign-in via the Experience API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:53:13 +02:00
hsiegeln
3384510f3c fix: passkeys work independently of MFA mode
All checks were successful
CI / build (push) Successful in 2m15s
CI / docker (push) Successful in 1m1s
When MFA mode is off but passkeys are enabled, WebAuthn + BackupCode
factors are still synced to Logto. Previously, MFA off cleared all
factors including WebAuthn, so passkey enrollment was never offered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:45:30 +02:00
hsiegeln
18e6f32f90 refactor: move passkey enrollment to sign-in UI via Experience API
All checks were successful
CI / build (push) Successful in 2m12s
CI / docker (push) Successful in 1m49s
Remove the SaaS backend proxy approach for passkey registration (Account
API binding, Management API proxy, password modal in PasskeySection).
Instead, offer passkey enrollment natively during sign-in via Logto's
Experience API — the correct architectural layer.

Sign-in flow: when Logto returns MFA enrollment available (422), show a
"Secure your account" screen with Register passkey / Set up later. Uses
Experience API WebAuthn registration endpoints. Works for all users
(SaaS and future server users) since the sign-in UI is shared.

PasskeySection in account settings now only manages existing passkeys
(list/rename/delete) and directs users to register during sign-in.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:33:46 +02:00
hsiegeln
4df6fc9e03 fix: proxy passkey bind through Management API
All checks were successful
CI / build (push) Successful in 2m17s
CI / docker (push) Successful in 1m29s
Logto's /api/my-account/ endpoints reject the opaque access token with
401 even though /api/verifications/ accepts it. The bind step now goes
through the SaaS backend which calls the Management API instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:23:41 +02:00
hsiegeln
2aa5100530 fix: add password re-verification before passkey registration
All checks were successful
CI / build (push) Successful in 2m28s
CI / docker (push) Successful in 1m32s
Logto Account API requires identity verification (logto-verification-id
header) for sensitive MFA operations. Adds a password prompt modal before
the WebAuthn ceremony — verifies password first, then proceeds with
passkey registration using the verification record ID.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:10:47 +02:00
hsiegeln
c360d9ad5f fix: override WebAuthn credential type for Logto Account API
All checks were successful
CI / build (push) Successful in 3m29s
CI / docker (push) Successful in 2m14s
@simplewebauthn/browser returns type: "public-key" (W3C standard) but
Logto's verify endpoint expects type: "WebAuthn".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:59:53 +02:00
hsiegeln
e7952dd9de fix: keep vendor sidebar active on account settings page
All checks were successful
CI / build (push) Successful in 1m54s
CI / docker (push) Successful in 1m26s
Vendor sidebar collapsed and tenant sidebar appeared when navigating to
/settings/account because onVendorRoute was false for non-/vendor paths.
Now vendor users stay on vendor sidebar for all routes except /tenant/*.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:18:09 +02:00
hsiegeln
687598952f fix: correct Account Center enablement — mfa field is a string enum
All checks were successful
CI / build (push) Successful in 2m6s
CI / docker (push) Successful in 1m6s
Logto's PATCH /api/account-center expects mfa as 'Off'|'ReadOnly'|'Edit',
not a nested object. Fixes 400 Bad Request on startup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:14:31 +02:00
hsiegeln
c22580e124 feat: always enable WebAuthn in MFA factors and add passkey registration
All checks were successful
CI / build (push) Successful in 2m3s
CI / docker (push) Successful in 1m26s
- Sync vendor auth policy to Logto sign-in experience on save and on
  startup. Always include WebAuthn + TOTP + BackupCode in MFA factors
  when MFA is enabled — no reason to gate passkeys behind a toggle.
- Enable Logto Account Center on startup for user-facing MFA management.
- Add passkey registration to account settings via Logto Account API.
  Frontend calls Logto directly (same domain) for the WebAuthn ceremony:
  generate options, browser credential creation, verify, and bind.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:01:58 +02:00
hsiegeln
a5c20830a7 fix: prevent MFA lockout and move enrollment to modal dialog
All checks were successful
CI / build (push) Successful in 1m58s
CI / docker (push) Successful in 1m47s
Three fixes for MFA enrollment and sign-in:

- Defer TOTP registration with Logto until after 6-digit code verification.
  Previously setupTotp() immediately registered the secret, so abandoning
  enrollment mid-way left MFA active without a working authenticator.
- Move entire MFA enrollment flow (QR code, verify, backup codes) into a
  Modal dialog instead of replacing the Card content inline.
- Fix sign-in MFA flow: submitMfa() no longer calls identifyUser() after
  TOTP verify — user is already identified, and passing the MFA
  verificationId to identification returned 422 ("method not activated").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 16:25:15 +02:00
hsiegeln
9231a1fc60 fix: move forgot password link below sign-in button
All checks were successful
CI / build (push) Successful in 2m0s
CI / docker (push) Successful in 1m7s
Repositions the "Forgot password?" link from above the sign-in button
to below it, matching the desired layout. Updates link style to be
centered with link color instead of right-aligned muted text.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 16:06:36 +02:00
f325416833 Merge pull request 'feature/vendor-admin-account-settings' (#60) from feature/vendor-admin-account-settings into main
All checks were successful
CI / build (push) Successful in 3m22s
CI / docker (push) Successful in 27s
Reviewed-on: #60
2026-04-27 15:58:05 +02:00
hsiegeln
ab800bbef9 fix: handle Logto data URI in MFA QR code display
All checks were successful
CI / build (push) Successful in 2m7s
CI / docker (push) Successful in 1m31s
CI / build (pull_request) Successful in 3m23s
CI / docker (pull_request) Has been skipped
Logto's secretQrCode is a data:image/png;base64 URI, not an otpauth://
string. QRCodeSVG crashes trying to encode it ("Data too long"). Now
renders data URIs as <img> and only uses QRCodeSVG for otpauth:// URIs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:43:39 +02:00
hsiegeln
15d6c7abc1 fix: remove explicit pagination from Logto role API calls
All checks were successful
CI / build (push) Successful in 2m3s
CI / docker (push) Successful in 59s
Logto's /api/roles/{id}/users endpoint rejects page=1 with
guard.invalid_pagination. Remove explicit pagination params and
let Logto use its defaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:40:05 +02:00
0b4d0e3b2f Merge pull request 'feat: vendor admin management and shared account settings' (#59) from feature/vendor-admin-account-settings into main
All checks were successful
CI / build (push) Successful in 2m15s
CI / docker (push) Successful in 20s
Reviewed-on: #59
2026-04-27 15:20:23 +02:00
hsiegeln
f823a409d0 fix: add AccountService mock to TenantPortalServiceTest constructor
All checks were successful
CI / build (push) Successful in 3m9s
CI / build (pull_request) Successful in 3m8s
CI / docker (pull_request) Has been skipped
CI / docker (push) Successful in 1m43s
The TenantPortalService constructor gained an AccountService parameter
in the consolidation refactor — the test was missing it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:15:19 +02:00
hsiegeln
e9e18f6c38 docs: update CLAUDE.md for account package, vendor admins, and shared components
Some checks failed
CI / build (push) Failing after 2m1s
CI / docker (push) Has been skipped
CI / build (pull_request) Failing after 1m46s
CI / docker (pull_request) Has been skipped
- Add account/ package to Key Packages table
- Add VendorAdminService/Controller to vendor/ package
- Note TenantPortalService delegation to AccountService
- Update ui/CLAUDE.md: AccountSettingsPage, VendorAdminsPage,
  Administrators sidebar, user menu dropdown, shared components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:09:41 +02:00
hsiegeln
372d3c77a0 fix: code review findings — dead catch blocks, notification email, role verification
- Remove dead IllegalArgumentException catch blocks in TenantPortalController
  (delegated methods now throw ResponseStatusException, handled by Spring)
- Add password reset notification email in VendorAdminService.resetAdminPassword
- Add verifyIsVendorAdmin guard to resetAdminPassword and resetAdminMfa
  to prevent platform admins from resetting arbitrary non-admin users

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:06:16 +02:00
hsiegeln
e5e0cad7c3 refactor: consolidate tenant SettingsPage to use shared account components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:59:09 +02:00
hsiegeln
8668642b8d feat: add account settings route and user menu dropdown
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:58:27 +02:00
hsiegeln
d44ee4b977 feat: add VendorAdminsPage with list, create/invite, remove, reset actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:56:03 +02:00
hsiegeln
5d1d263c74 feat: add AccountSettingsPage composing shared account components 2026-04-27 14:54:26 +02:00
hsiegeln
e563631efb feat: extract shared account components (Profile, Password, MFA, Passkey)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:53:05 +02:00
hsiegeln
bf42f13afc feat: add TypeScript types and React Query hooks for account and vendor admin APIs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:49:44 +02:00
hsiegeln
0da1ffea7f fix: guard against null orgId in createAndInviteUser and createUserWithPassword
Vendor admins use global roles, not org roles — passing null orgId
would previously cause addUserToOrganization to call
/api/organizations/null/users and fail.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 14:48:00 +02:00
hsiegeln
022b6d9722 feat: add vendor admin management (list, create/invite, remove, reset password/MFA)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:46:42 +02:00
hsiegeln
665ffefd3e refactor: use AccountService for display name in OnboardingService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:46:20 +02:00
hsiegeln
cc3d2dc111 refactor: delegate TenantPortalService MFA/password/passkey methods to AccountService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:44:20 +02:00
hsiegeln
ab240e42b0 feat: add /api/account/** security config and MFA enforcement exemptions
Permit /settings/** SPA route, gate /api/account/** as authenticated,
and exempt account MFA/profile/password paths from MFA enforcement filter.
2026-04-27 14:41:21 +02:00
hsiegeln
b63e5e9c81 feat: add AccountController with /api/account/* endpoints 2026-04-27 14:41:05 +02:00
hsiegeln
90d84ffd00 feat: add AccountService extracting user identity operations from TenantPortalService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:39:40 +02:00
hsiegeln
19428b4e27 feat: add password verify and role management methods to LogtoManagementClient
Adds verifyUserPassword (for current-password check before password change) and
four global role methods (listRoleUsers, getRoleByName, assignGlobalRole,
revokeGlobalRole) needed by the upcoming AccountService and VendorAdminService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:36:59 +02:00
hsiegeln
316e5ef6c1 docs: implementation plan for vendor admin management and account settings
16 tasks covering: LogtoManagementClient additions, AccountService
extraction, AccountController, VendorAdminService/Controller,
SecurityConfig updates, frontend component extraction, shared
AccountSettingsPage, VendorAdminsPage, and Layout user menu.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 14:32:46 +02:00
hsiegeln
86d9ba4985 docs: vendor admin management and account settings design spec
Two features: multi-vendor admin management (invite/create, remove,
reset password/MFA) and shared account settings page (profile, password
change with current-password verification, MFA self-service). Includes
consolidation plan extracting user-level identity operations from
TenantPortalService into new AccountService.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 14:20:49 +02:00
hsiegeln
292adeea4c docs: update documentation for passkey MFA feature
All checks were successful
CI / build (push) Successful in 2m23s
CI / docker (push) Successful in 2m19s
- Add V002/V003 migrations and VendorAuthPolicy classes to CLAUDE.md
- Document MFA & passkey enforcement model in config CLAUDE.md
- Mark passkey MFA design spec as Implemented

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 11:51:12 +02:00
hsiegeln
43a1058f33 fix: code review findings — auth-settings HTTP method, authorization, redirect
- Change auth-settings endpoint from PUT to PATCH (matches partial update semantics and frontend hook)
- Add @PreAuthorize("SCOPE_tenant:manage") to updateAuthSettings endpoint
- Consolidate MFA/passkey 403 redirect handling in API client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 09:01:23 +02:00
hsiegeln
60a800f757 feat: add passkey offer step to onboarding wizard
After tenant creation, checks vendor auth policy and conditionally
shows a passkey enrollment offer screen before redirecting. User
can skip and set up later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 08:55:24 +02:00
hsiegeln
76a62135ab feat: add WebAuthn and method picker modes to sign-in UI
Adds mfaWebauthn and mfaMethodPicker modes with smart routing based on
stored preference (localStorage). Auto-triggers passkey prompt on mode
entry. Adds "Use passkey instead" link in TOTP mode. Saves method
preference on successful verification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 08:55:16 +02:00