mirror of
https://github.com/zitadel/zitadel.git
synced 2025-07-15 17:48:35 +00:00

# Which Problems Are Solved Currently if a user signs in using an IdP, once they sign out of Zitadel, the corresponding IdP session is not terminated. This can be the desired behavior. In some cases, e.g. when using a shared computer it results in a potential security risk, since a follower user might be able to sign in as the previous using the still open IdP session. # How the Problems Are Solved - Admins can enabled a federated logout option on SAML IdPs through the Admin and Management APIs. - During the termination of a login V1 session using OIDC end_session endpoint, Zitadel will check if an IdP was used to authenticate that session. - In case there was a SAML IdP used with Federated Logout enabled, it will intercept the logout process, store the information into the shared cache and redirect to the federated logout endpoint in the V1 login. - The V1 login federated logout endpoint checks every request on an existing cache entry. On success it will create a SAML logout request for the used IdP and either redirect or POST to the configured SLO endpoint. The cache entry is updated with a `redirected` state. - A SLO endpoint is added to the `/idp` handlers, which will handle the SAML logout responses. At the moment it will check again for an existing federated logout entry (with state `redirected`) in the cache. On success, the user is redirected to the initially provided `post_logout_redirect_uri` from the end_session request. # Additional Changes None # Additional Context - This PR merges the https://github.com/zitadel/zitadel/pull/9841 and https://github.com/zitadel/zitadel/pull/9854 to main, additionally updating the docs on Entra ID SAML. - closes #9228 - backport to 3.x --------- Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com> Co-authored-by: Zach Hirschtritt <zachary.hirschtritt@klaviyo.com>
114 lines
3.9 KiB
Go
114 lines
3.9 KiB
Go
// Package cache provides abstraction of cache implementations that can be used by zitadel.
|
|
package cache
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/zitadel/logging"
|
|
)
|
|
|
|
// Purpose describes which object types are stored by a cache.
|
|
type Purpose int
|
|
|
|
//go:generate enumer -type Purpose -transform snake -trimprefix Purpose
|
|
const (
|
|
PurposeUnspecified Purpose = iota
|
|
PurposeAuthzInstance
|
|
PurposeMilestones
|
|
PurposeOrganization
|
|
PurposeIdPFormCallback
|
|
PurposeFederatedLogout
|
|
)
|
|
|
|
// Cache stores objects with a value of type `V`.
|
|
// Objects may be referred to by one or more indices.
|
|
// Implementations may encode the value for storage.
|
|
// This means non-exported fields may be lost and objects
|
|
// with function values may fail to encode.
|
|
// See https://pkg.go.dev/encoding/json#Marshal for example.
|
|
//
|
|
// `I` is the type by which indices are identified,
|
|
// typically an enum for type-safe access.
|
|
// Indices are defined when calling the constructor of an implementation of this interface.
|
|
// It is illegal to refer to an idex not defined during construction.
|
|
//
|
|
// `K` is the type used as key in each index.
|
|
// Due to the limitations in type constraints, all indices use the same key type.
|
|
//
|
|
// Implementations are free to use stricter type constraints or fixed typing.
|
|
type Cache[I, K comparable, V Entry[I, K]] interface {
|
|
// Get an object through specified index.
|
|
// An [IndexUnknownError] may be returned if the index is unknown.
|
|
// [ErrCacheMiss] is returned if the key was not found in the index,
|
|
// or the object is not valid.
|
|
Get(ctx context.Context, index I, key K) (V, bool)
|
|
|
|
// Set an object.
|
|
// Keys are created on each index based in the [Entry.Keys] method.
|
|
// If any key maps to an existing object, the object is invalidated,
|
|
// regardless if the object has other keys defined in the new entry.
|
|
// This to prevent ghost objects when an entry reduces the amount of keys
|
|
// for a given index.
|
|
Set(ctx context.Context, value V)
|
|
|
|
// Invalidate an object through specified index.
|
|
// Implementations may choose to instantly delete the object,
|
|
// defer until prune or a separate cleanup routine.
|
|
// Invalidated object are no longer returned from Get.
|
|
// It is safe to call Invalidate multiple times or on non-existing entries.
|
|
Invalidate(ctx context.Context, index I, key ...K) error
|
|
|
|
// Delete one or more keys from a specific index.
|
|
// An [IndexUnknownError] may be returned if the index is unknown.
|
|
// The referred object is not invalidated and may still be accessible though
|
|
// other indices and keys.
|
|
// It is safe to call Delete multiple times or on non-existing entries
|
|
Delete(ctx context.Context, index I, key ...K) error
|
|
|
|
// Truncate deletes all cached objects.
|
|
Truncate(ctx context.Context) error
|
|
}
|
|
|
|
// Entry contains a value of type `V` to be cached.
|
|
//
|
|
// `I` is the type by which indices are identified,
|
|
// typically an enum for type-safe access.
|
|
//
|
|
// `K` is the type used as key in an index.
|
|
// Due to the limitations in type constraints, all indices use the same key type.
|
|
type Entry[I, K comparable] interface {
|
|
// Keys returns which keys map to the object in a specified index.
|
|
// May return nil if the index in unknown or when there are no keys.
|
|
Keys(index I) (key []K)
|
|
}
|
|
|
|
type Connector int
|
|
|
|
//go:generate enumer -type Connector -transform snake -trimprefix Connector -linecomment -text
|
|
const (
|
|
// Empty line comment ensures empty string for unspecified value
|
|
ConnectorUnspecified Connector = iota //
|
|
ConnectorMemory
|
|
ConnectorPostgres
|
|
ConnectorRedis
|
|
)
|
|
|
|
type Config struct {
|
|
Connector Connector
|
|
|
|
// Age since an object was added to the cache,
|
|
// after which the object is considered invalid.
|
|
// 0 disables max age checks.
|
|
MaxAge time.Duration
|
|
|
|
// Age since last use (Get) of an object,
|
|
// after which the object is considered invalid.
|
|
// 0 disables last use age checks.
|
|
LastUseAge time.Duration
|
|
|
|
// Log allows logging of the specific cache.
|
|
// By default only errors are logged to stdout.
|
|
Log *logging.Config
|
|
}
|