Commit Graph

4 Commits

Author SHA1 Message Date
Anso 7cd42699d1 fix(sso): preserve admin-assigned roles across SSO sign-in (#1862)
* fix(sso): preserve admin-assigned roles across SSO sign-in

An SSO/OIDC/LDAP user's role was overwritten by the IdP-derived role on
every sign-in, so a role an admin assigned in Settings > Users reverted to
the provider default on the next login. Gate role re-sync behind an opt-in
sso_role_sync setting (default off), so manual role edits persist unless the
operator explicitly enables IdP-authoritative sync. Email continues to sync
unconditionally.

Adds human-session-only GET/PUT /api/sso/config/role-sync endpoints with a
hub-side API-token rejection in the remote proxy, a frontend toggle, a
regenerated SSO settings screenshot, and matching docs.

Closes #1851

* fix(sso): satisfy CodeQL on role-sync log and test token hashing

Route three inline API-token creation blocks through the shared
createTestApiToken helper so the sha256 hashing lives in one place, and
log the role-sync toggle as a word instead of a raw boolean. No behavior
change; resolves the CodeQL js/insecure-hashing and log-injection alerts.

* fix(sso): harden role-sync gate, name the toggle, fix screenshot

Addresses pre-merge review findings on the SSO role-sync feature:
- Make the hub-side SSO config authz guard case-insensitive to match
  Express routing semantics, closing a case-variant API-token bypass.
- Give the IdP role-sync switch an accessible name.
- Capture the SSO settings screenshot at desktop size with the scroll
  area expanded so the role-sync control is fully visible.
2026-08-28 09:26:22 -04:00
Anso e175db8e62 feat(auth): add SSO-only authentication mode (#1714)
* feat(auth): add SSO-only authentication mode

Let administrators disable interactive local password login when SSO is configured, with backend enforcement, activation safeguards, and host CLI recovery.

Closes #1709

* fix: resolve CI failures in auth mode PR

- Add useLicense mock to SSOSection test to prevent crash from
  AuthenticationModePanel rendering without LicenseProvider
- Remove username from authMode console.log calls that CodeQL flags
  as clear-text logging of sensitive information

* fix(auth): keep SSO-only on named disableSso and fail-closed login

Named provider disable no longer reverts authentication_mode. Login initializes localLoginEnabled false so a status fetch failure cannot reveal the password form. Center a single OIDC provider button on the login card.

* fix(auth): move SSO-only authentication mode from Admiral to Community tier

Security-hardening features belong on the Community tier per the existing
Community rebalance. The reporter of #1709 noted that disabling local
password login after configuring SSO is a basic security measure, not an
enterprise governance feature. LDAP provider configuration remains
Admiral-gated via requireTierForSsoProvider.

* fix(ui): keep SSO Active badge and ON toggle in sync

Provider cards mounted before config fetch finished with enabled:false, so a saved Active provider showed OFF until the local draft was resynced. Drive both the badge and TogglePill from the synced local config.

* feat(auth): auto-redirect to sole OIDC provider under SSO-only

When authentication mode is SSO only and exactly one OIDC provider is enabled (no LDAP), skip the login chooser and send the browser to that provider's authorize URL. Returning sso_error stays on the login page so the failure message remains visible.

* fix(ui): move oidcAutoRedirectUrl out of Login for fast refresh

Exporting the helper alongside the Login component tripped react-refresh/only-export-components and failed Frontend lint CI. Keep Login as a component-only module and colocate the helper with its unit tests under lib/.
2026-07-28 10:01:05 -04:00
Anso 865d792874 feat(pricing): collapse to two tiers (#1309)
* feat(pricing): collapse to two tiers (Community + Admiral)

Collapse Sencho's pricing from three tiers (Community / Skipper / Admiral)
to two: a generous free Community tier and a single paid Admiral tier. The
Skipper tier is removed.

Now free in Community: auto-heal, auto-update, scheduled operations,
webhooks, notification routing, Fleet Actions and bulk operations, SSO
preset providers (Google / GitHub / Okta), unlimited users with admin and
viewer roles, and deploy safety (atomic deploys, auto-rollback, and
one-click rollback).

Admiral (paid) is focused on running and governing a fleet: blueprints,
Fleet Secrets, deploy enforcement, vulnerability report export, audit log,
host console, private registries, mesh networking, node cordon, managed
cloud backup, LDAP / Active Directory SSO, and the advanced RBAC roles
(deployer, node-admin, auditor) with per-resource scoped assignments.

Internally the license variant distinction is removed so tier is binary
(community / paid). License validation still verifies the Lemon Squeezy
store and product before granting paid status.

Docs and the contributor guide are updated to the two-tier model.

* docs(pricing): correct licensing page to two-tier pricing and tidy stale tier wording

The licensing docs page kept the old Admiral pricing plus a Founder
Lifetime column and an Enterprise paragraph after the two-tier collapse.
Update it to $12/month or $99/year, drop the lifetime and Enterprise
content, and link to the pricing page for current pricing.

Also fix stale "Skipper" wording in CLA.md, SUPPORT.md, one test title,
and three test comments. Historical CHANGELOG entries and the
retired-Skipper license-guard test are intentionally left as-is.

* docs: align licensing and SSO pages with the two-tier model

Correct the SSO overview so the Google, GitHub, and Okta presets read as
available on every tier, matching the provider table; only LDAP and Active
Directory require Sencho Admiral. Remove the lifetime-plan references from the
licensing, settings, and troubleshooting pages so they reflect subscription-only
Admiral pricing.

* fix(rbac): omit scoped permissions from /me on the Community tier

Scoped role assignments only take effect on the paid tier, but GET /api/permissions/me returned them unconditionally, so a downgraded instance with leftover assignments rendered per-resource affordances the API then rejected with 403. The endpoint now mirrors the permission middleware and includes scoped permissions only on the paid tier. Adds a regression test covering the downgrade case.

* docs: use custom-pricing wording on the contact page

The two-tier model has no Enterprise tier; reword the contact page's enterprise pricing/deals to custom pricing/deals so it does not imply a tier that no longer exists.
2026-06-04 17:45:53 -04:00
Anso 4248ac0e72 fix(sso): surface config load, test, and removal errors in the SSO settings UI (#1265)
The SSO provider settings previously swallowed three failure paths: the
provider-config load on mount, the connection test, and provider removal.
A transient backend error, a tier-gate rejection, or a failed removal left
the admin with no feedback at all.

Each path now surfaces the backend message (or a clear fallback) through the
standard error toast, matching the existing save handler. The connection-test
handler also checks the response status before treating the body as a test
result, so an API or authorization failure is no longer reported as a failed
identity-provider connection.

Adds component tests covering the non-ok and network-failure branches for each
handler, including the unparseable-error-body fallback.
2026-06-01 09:00:35 -04:00