- removes a stray assignment that overwrote isCertExtendable with a literal true on every OIDC certificate authentication
- reports isCertExtendable as false over OIDC for cert authenticators not issued by the network, matching legacy cert auth
- adds coverage asserting the z_ice claim and current-api-session both report a 3rd party CA certificate as not extendable
- caps buffered HTTP request bodies at 1 MiB across the client, management, fabric management, and OIDC web APIs
- rejects oversized bodies with 413 REQUEST_ENTITY_TOO_LARGE before authentication
- surfaces request body read errors instead of ignoring them
- returns after writing the request context error response in the client API handler
- adds integration coverage for oversized bodies with and without Content-Length
* fixesopenziti/ziti#3990 push service and posture state to subscribed SDKs
- pushes indexed atomic ServiceChangeSet envelopes to subscribed SDK connections: a full snapshot on subscribe, incremental service changes per RDM scan pass, posture check definition changes as their own entries, and identity-resolved config bodies, all serialized so envelopes hit the wire in index order
- pushes per-connection PostureStateChange state (monotonic seq, resync on request) for posture pass/fail, including flips caused by definition edits that mutate no posture data
- registers pending RDM identity subscriptions for identities not yet synced to the router and sends an authoritative full sync plus full posture state when the identity arrives; an active push subscription pins the connection's RDM listener
- advertises service subscriptions and router data model support on the control-channel capability bitmask; the controller persists each router's capabilities mask and version on the EdgeRouter entity via raft and renders them on the edge APIs, so SDKs can select capable routers before connecting
- submits posture per router and corrects MFA posture semantics: pushed expiry is the earliest of timeout and pending wake/unlock grace deadlines, wake/unlock re-pass satisfies the re-prompt, api session tokens whose amr attests TOTP seed the MFA baseline from auth_time only (never iat), and token exchange carries the subject token's auth_time
- sends structured denials on dial and bind refusals: posture failures carry the failing check ids, no-policy denials are access denied, unknown services are invalid service, and session token failures are invalid session; the denial's cause no longer rides the wire as an unserializable error
- hard-closes accepted SDK connections on edge listener shutdown so clients observe a router going away immediately
- adds integration coverage: subscription snapshots and change delivery, poll and push reconciliation as capable routers come and go, posture state and definition-change push, router views over the public SDK API, typed dial errors, MFA baseline seeding, and OIDC token-exchange auth_time preservation
- removed RDM capability from SDK, router/controller only
KeySet() formatted a peer controller's SHA1 cert fingerprint with %s
instead of %x, producing an undecodable raw-byte kid in the /oidc/keys
JWKS response for every entry sourced from GetPeerSigners(). The
error-path logging four lines below this already used %x correctly.
In a multi-controller raft HA deployment, each controller signs
OIDC/OTT JWTs with its own root ctrl-plane-identity key. A JWKS lookup
landing on a controller other than the signer sees the true signer's
key advertised under this corrupt kid and cannot match it against the
token's kid header, failing verification.
Fixes#4067
Co-authored-by: Björn Mage <4495532+bjornmage@users.noreply.github.com>
The router's CheckConnections reaper enforced only JWT expiry, so a revoked OIDC
api-session, or a disabled/deleted identity, kept its live circuits and hosted
terminators until the access token expired. The router now enforces the
RouterDataModel revocations directly, tightening access-loss propagation to the
reaper interval.
- adds a Type field to DataState_Revocation and the raft Revocation command
proto, mirroring rest_model.RevocationTypeEnum (API_SESSION/IDENTITY/JTI) so the
management API, OIDC producers, sync, and router enforcement share one
vocabulary; the common.RevocationType* constants are compile-time bound to the
enum to prevent drift
- adds an IssuedBefore cutoff so an identity revocation invalidates only sessions
issued before it; a session re-authenticated after the cutoff survives the
still-lingering revocation. Persists IssuedBefore on the db and model Revocation
and carries it (plus the Type) through the single and batched raft marshalling
- adds RouterDataModel.IsApiSessionRevoked and IsIdentityRevoked and enforces both
in CheckConnections, closing a revoked session's connections
- revokes a deleted or disabled identity's live OIDC sessions via an
IdentityRevocationConstraint in the db package, run as a store pre-commit
constraint so the revocation is written in the same transaction as the identity
change and cannot be skipped (self-contained OIDC JWTs aren't otherwise
reachable). NewIdentityManager installs it with the revocation type and lifetime
- has the OIDC end-session (TerminateSessionFromRequest) revoke the specific
api-session named by the z_asid claim, with an identity-scoped fallback; sets
IssuedBefore on the identity fallback and the management revocation API; adds
RevocationManager.CreateOrReplace, routed through by both the OIDC paths and the
management revocation API, so a repeat logout/termination/revocation refreshes
the cutoff rather than colliding on the reused id. Expiry derives from the
longest configured token duration via a shared common.MaxTokenDuration helper
- adds tests/revocation_enforcement_oidc_test.go covering api-session revocation
(and a fresh session staying unaffected), identity disable and delete, and the
identity cutoff (a post-cutoff session surviving the lingering revocation)
* fixes#3809 support CSR submission during OIDC authentication
- accepts an optional CSR during OIDC login (all auth methods) and
signs it into a session-bound certificate with a SPIFFE ID derived
from the identity and API session
- returns the signed certificate PEM as a top-level "session_cert"
field in the token endpoint JSON response (CodeExchange, RefreshToken,
TokenExchange)
- adds cert-binding verification on RefreshToken and TokenExchange:
if z_cfs is present the peer cert fingerprint must match (strict),
otherwise falls back to SPIFFE ID verification
- supports cert rotation via csr_pem form parameter on refresh and
token exchange; replaces the session cert fingerprint while
preserving the authenticating cert fingerprint
- adds AuthCertFingerprints (z_acfs) claim to track permanent auth
cert fingerprints separately from rotatable session cert fingerprints
- only the leaf certificate fingerprint is added to z_cfs and z_acfs,
intermediates are never included
- invalid CSR returns 400 Bad Request in OIDC error format
- propagates updated CustomClaims (including CertFingerprints) from
access token to renewed refresh token so rotated fingerprints are
enforced on subsequent refreshes
- adds CertGenerated field to ApiSessionEvent
- advertises OIDC_AUTH_WITH_CSR controller capability when OIDC is
enabled
- adds unit tests for verifyCertBinding (fingerprint, SPIFFE ID,
edge cases) and CsrPem field parsing
- adds integration tests for initial CSR auth (updb, cert, ext-jwt),
cert-binding on refresh/exchange, CSR rotation with cert auth,
SPIFFE fallback and z_cfs transition, and CSR property forging
resistance
* address pr concerns
* add z_cfs len tests on junk chain certs
* strip csr subject info, replace w/ santized values
* fix csr rotation rejection/paths during token exchange/refresh
- gates OIDC `z_cfs` claim on cert-based primary auth so non-cert sessions don't bind TLS-presented certs
- reorders router api session validation: fingerprint match first, then SPIFFE-on-first-party as fallback
- accepts first-party SPIFFE-Identity match as an acceptance signal (previously fell through to fingerprint check)
* fixes#3734 enforce client certificate proof-of-possession for OIDC sessions
- adds verifyCertProofOfPossession() in resolveOidcSession() to require
TLS client cert matching a z_cfs fingerprint or SPIFFE ID when the
OIDC token was issued with cert bindings
- adds z_cae (CertAllowExpired) claim from auth policy, propagated
through token issuance and refresh
- adds TrustCache.VerifyClientCert() with tiered pool matching
(first-party roots, trust anchors, third-party) and TTL cache
- adds WrapIdentityWithCertValidation() on the router to verify client
certs at the TLS level against RDM PublicKeys
- adds IsFirstPartyCert() on the router to gate SPIFFE ID matching by
checking whether the cert chains to the controller root CA
- adds VerifySpiffeId() in common/spiffehlp with SpiffeMatchApiSession,
SpiffeMatchIdentity, and SpiffeMatchNone return types
- adds SPIFFE IDs to OTT and token enrollment certs (/identity/<id>)
- enforces cert expiry by match type: API session certs must be valid,
fingerprint-matched certs respect z_cae, legacy sessions skip checks
- shallow-copies leaf certs before overriding time fields in all cert
verification paths to avoid races on shared x509.Certificate pointers
- fixes controllerRootCache setting inited=true before the ctrl channel
is available, which permanently cached the failure
* fixes#3806 expose OpenZiti endpoints in OIDC discovery document
- adds vendor-specific "openziti_endpoints" field to the
/.well-known/openid-configuration response
- overrides Discovery() on the OIDC server to wrap the standard config
with OpenZiti login and MFA endpoint URLs
- advertises password, cert, ext-jwt, totp, totp enrollment, and
auth query endpoints as absolute URLs derived from the issuer
- adds integration test verifying all openziti_endpoints fields
- adds dual-server integration test confirming endpoint URLs reflect
the correct issuer when edge-oidc is hosted on multiple bind points
* changelog
- migrates from op.NewProvider() to LegacyServer/RegisterLegacyServer,
routing all OIDC endpoint errors through op.WriteError which maps
server_error to HTTP 500 and supports custom status codes via
op.StatusError
- returns oidc.ErrInvalidClient() from AuthorizeClientIDSecret for
unknown clients and bad secrets (HTTP 400 with invalid_client)
- returns oidc.ErrInvalidGrant() from parseRefreshToken,
parseAccessToken, createAccessToken, and renewRefreshToken for
client-supplied token errors (HTTP 400 with invalid_grant)
- fixes copy-paste bug in parseAccessToken that reported "invalid
refresh_token" for access token errors
- plain Go errors from server-side failures (identity read, JSON
marshal, token signing, Raft dispatch) now correctly surface as
HTTP 500 via WriteError's DefaultToServerError handling
- adds integration tests covering error codes for token endpoint,
login endpoint, userinfo endpoint, and end_session endpoint
- adds DeleteRevocationsBatchCommand so expired-revocation cleanup goes
through raft as a single log entry per batch
- adds CreateRevocationsBatchCommand for batched revocation creation
through raft
- moves refresh-token revocations from synchronous inline creation to a
background batcher that flushes on a configurable interval, removing
the database and raft as a bottleneck on token refreshes
- skips revocation creation for tokens expiring within a configurable
threshold (revocationMinTokenLifetime), since they become invalid on
their own
- validates that revocationMinTokenLifetime is less than 50% of the
configured refresh token lifetime
- makes the revocation enforcer frequency configurable and restricts it
to run only on the raft leader
- adds tests for multi-batch delete, batched create with router RDM
propagation, and skip-threshold behavior
- adds new configuration tunables under edge.oidc: revocationBucketInterval,
revocationMinTokenLifetime, revocationBucketMaxSize, revocationMaxQueued,
revocationEnforcerFrequency
- fixes RevokeToken double-write: adds return after JWTID-keyed revocation
save, preventing fallthrough write with raw JWT string as unreachable key
- fixes TerminateSession key mismatch: stores revocation by identityId alone,
matching the Subject-based lookup in ValidateAccessToken
- fixes RevocationDelete sync action: passes DataState_Delete instead of
DataState_Create so routers evict the entry from their data model
- adds RevocationManager.DeleteExpired: batch-deletes expired revocations in
batches of 500 until none remain
- adds RevocationEnforcer: periodic policy runner (every 1 minute) that calls
DeleteExpired and records metrics
before test fixes
* fixes#3496 allow TOTP enroll mid OIDC
- detects unenrolled TOTP mid-OIDC flow and redirects to enroll endpoints
- adds enroll/verify endpoints in oidc_auth/login.go
- centralizes auth query storage rendering in oidc_auth/storage.go
- adds SDK integration tests for enrollment success, re-auth, cancelled
enrollment, empty/alpha/wrong codes, and missing provider
- removes reduce rp server usage in tests
- refactors some oidc tests to new style where possible
- fixes amr regression in 2.0
- adds test for amr and auth_time
* fixesopenziti/ziti#3356 adds www-authenticate headers
- www-authenticate headers are returned on 401s from API requests
- www-authenticate headers are returned during authentication to signal
addtional JWT bearer tokens needed (secondary ext jwt)
- adds support for additional headers on API errors
- adds SecurityTokenCtx for centralized security header processing
(legacy, jwt, etc.)
- adds SecurityCtx for centralized identity, auth policy, MFA handling
- refactors existing JWT authentication methods (oidc, legacy) to use
centralized processing where possible
Harden OIDC token endpoint against panics and silent failures
- Wrap OIDC handler with TimeoutHandler to match all other API handlers
- Fix GetRootTlsJwtSigner using rootCerts[0] instead of resolved rootCert
- Propagate Generate() errors in createRefreshClaims and renewRefreshToken
- Use safe type assertion for kid header in JwtSignerKeyFunc
* fix#3231 use root controller server certs for OIDC signing
- addresses HA vs non-HA signing
- fixes issue where APIs server w/ difference certs than the root
identity
- adds documentation for env/appenv
- adds a new composite type for TLSCert JWT signers
* address possible nil reference
* remove ineff assignment on jwt signing method
* fix#3178 apis missing from controllers, fixes#3193 adds totp auth query enrollment flag
- fixed controller store to no longer blank apis on all CUD actions
- controllers now report their current config state on leader change to
avoid stale information
- fixes peer disconnect to only set online state
- adds enrollment state flags to auth queries
- adds test for OIDC MFA enrollment/recovery/delete
- adds controller store unit tests
fixes#3084 adds events and improper chain flag
- splits cert resolution into root, legacy root + intermediate,
and third-party pool. Allowing the detection of client authentication
with incomplete chains if root + intermediate succeeds after root only fails
- adds `improperClientCertChain` to API Sessions and Current API Session.
Added for OIDC and legacy auth. Set to true when a client certificate is used
that was issued by the network and did not pass the root-only pool.
- updates current-api session logic to use new value
- sets z_authid in access/refresh tokens
- updates tests to ensure authenticator id is set on access/refres
* fixes#2737 open-id config issuer mismatch
- scans all SANs for possible supported hostname/ips
- add copyright, add better accept handling
- re-arrange where issuers are determined
- removes support for root openid-config
- fixes issuer mapping
- fixes endpoint tests
- add support for wild card certificates influencing issuers