package project import ( "context" "time" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/zerrors" ) const ( OIDCConfigAddedType = applicationEventTypePrefix + "config.oidc.added" OIDCConfigChangedType = applicationEventTypePrefix + "config.oidc.changed" OIDCConfigSecretChangedType = applicationEventTypePrefix + "config.oidc.secret.changed" OIDCClientSecretCheckSucceededType = applicationEventTypePrefix + "oidc.secret.check.succeeded" OIDCClientSecretCheckFailedType = applicationEventTypePrefix + "oidc.secret.check.failed" ) type OIDCConfigAddedEvent struct { eventstore.BaseEvent `json:"-"` Version domain.OIDCVersion `json:"oidcVersion,omitempty"` AppID string `json:"appId"` ClientID string `json:"clientId,omitempty"` ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` RedirectUris []string `json:"redirectUris,omitempty"` ResponseTypes []domain.OIDCResponseType `json:"responseTypes,omitempty"` GrantTypes []domain.OIDCGrantType `json:"grantTypes,omitempty"` ApplicationType domain.OIDCApplicationType `json:"applicationType,omitempty"` AuthMethodType domain.OIDCAuthMethodType `json:"authMethodType,omitempty"` PostLogoutRedirectUris []string `json:"postLogoutRedirectUris,omitempty"` DevMode bool `json:"devMode,omitempty"` AccessTokenType domain.OIDCTokenType `json:"accessTokenType,omitempty"` AccessTokenRoleAssertion bool `json:"accessTokenRoleAssertion,omitempty"` IDTokenRoleAssertion bool `json:"idTokenRoleAssertion,omitempty"` IDTokenUserinfoAssertion bool `json:"idTokenUserinfoAssertion,omitempty"` ClockSkew time.Duration `json:"clockSkew,omitempty"` AdditionalOrigins []string `json:"additionalOrigins,omitempty"` SkipNativeAppSuccessPage bool `json:"skipNativeAppSuccessPage,omitempty"` } func (e *OIDCConfigAddedEvent) Payload() interface{} { return e } func (e *OIDCConfigAddedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { return nil } func NewOIDCConfigAddedEvent( ctx context.Context, aggregate *eventstore.Aggregate, version domain.OIDCVersion, appID string, clientID string, clientSecret *crypto.CryptoValue, redirectUris []string, responseTypes []domain.OIDCResponseType, grantTypes []domain.OIDCGrantType, applicationType domain.OIDCApplicationType, authMethodType domain.OIDCAuthMethodType, postLogoutRedirectUris []string, devMode bool, accessTokenType domain.OIDCTokenType, accessTokenRoleAssertion bool, idTokenRoleAssertion bool, idTokenUserinfoAssertion bool, clockSkew time.Duration, additionalOrigins []string, skipNativeAppSuccessPage bool, ) *OIDCConfigAddedEvent { return &OIDCConfigAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, OIDCConfigAddedType, ), Version: version, AppID: appID, ClientID: clientID, ClientSecret: clientSecret, RedirectUris: redirectUris, ResponseTypes: responseTypes, GrantTypes: grantTypes, ApplicationType: applicationType, AuthMethodType: authMethodType, PostLogoutRedirectUris: postLogoutRedirectUris, DevMode: devMode, AccessTokenType: accessTokenType, AccessTokenRoleAssertion: accessTokenRoleAssertion, IDTokenRoleAssertion: idTokenRoleAssertion, IDTokenUserinfoAssertion: idTokenUserinfoAssertion, ClockSkew: clockSkew, AdditionalOrigins: additionalOrigins, SkipNativeAppSuccessPage: skipNativeAppSuccessPage, } } func (e *OIDCConfigAddedEvent) Validate(cmd eventstore.Command) bool { c, ok := cmd.(*OIDCConfigAddedEvent) if !ok { return false } if e.Version != c.Version { return false } if e.AppID != c.AppID { return false } if e.ClientID != c.ClientID { return false } if e.ClientSecret != c.ClientSecret { return false } if len(e.RedirectUris) != len(c.RedirectUris) { return false } for i, uri := range e.RedirectUris { if uri != c.RedirectUris[i] { return false } } if len(e.ResponseTypes) != len(c.ResponseTypes) { return false } for i, typ := range e.ResponseTypes { if typ != c.ResponseTypes[i] { return false } } if len(e.GrantTypes) != len(c.GrantTypes) { return false } for i, typ := range e.GrantTypes { if typ != c.GrantTypes[i] { return false } } if e.ApplicationType != c.ApplicationType { return false } if e.AuthMethodType != c.AuthMethodType { return false } if len(e.PostLogoutRedirectUris) != len(c.PostLogoutRedirectUris) { return false } for i, uri := range e.PostLogoutRedirectUris { if uri != c.PostLogoutRedirectUris[i] { return false } } if e.DevMode != c.DevMode { return false } if e.AccessTokenType != c.AccessTokenType { return false } if e.AccessTokenRoleAssertion != c.AccessTokenRoleAssertion { return false } if e.IDTokenRoleAssertion != c.IDTokenRoleAssertion { return false } if e.IDTokenUserinfoAssertion != c.IDTokenUserinfoAssertion { return false } if e.ClockSkew != c.ClockSkew { return false } if len(e.AdditionalOrigins) != len(c.AdditionalOrigins) { return false } for i, origin := range e.AdditionalOrigins { if origin != c.AdditionalOrigins[i] { return false } } return e.SkipNativeAppSuccessPage == c.SkipNativeAppSuccessPage } func OIDCConfigAddedEventMapper(event eventstore.Event) (eventstore.Event, error) { e := &OIDCConfigAddedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := event.Unmarshal(e) if err != nil { return nil, zerrors.ThrowInternal(err, "OIDC-BFd15", "unable to unmarshal oidc config") } return e, nil } type OIDCConfigChangedEvent struct { eventstore.BaseEvent `json:"-"` Version *domain.OIDCVersion `json:"oidcVersion,omitempty"` AppID string `json:"appId"` RedirectUris *[]string `json:"redirectUris,omitempty"` ResponseTypes *[]domain.OIDCResponseType `json:"responseTypes,omitempty"` GrantTypes *[]domain.OIDCGrantType `json:"grantTypes,omitempty"` ApplicationType *domain.OIDCApplicationType `json:"applicationType,omitempty"` AuthMethodType *domain.OIDCAuthMethodType `json:"authMethodType,omitempty"` PostLogoutRedirectUris *[]string `json:"postLogoutRedirectUris,omitempty"` DevMode *bool `json:"devMode,omitempty"` AccessTokenType *domain.OIDCTokenType `json:"accessTokenType,omitempty"` AccessTokenRoleAssertion *bool `json:"accessTokenRoleAssertion,omitempty"` IDTokenRoleAssertion *bool `json:"idTokenRoleAssertion,omitempty"` IDTokenUserinfoAssertion *bool `json:"idTokenUserinfoAssertion,omitempty"` ClockSkew *time.Duration `json:"clockSkew,omitempty"` AdditionalOrigins *[]string `json:"additionalOrigins,omitempty"` SkipNativeAppSuccessPage *bool `json:"skipNativeAppSuccessPage,omitempty"` } func (e *OIDCConfigChangedEvent) Payload() interface{} { return e } func (e *OIDCConfigChangedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { return nil } func NewOIDCConfigChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, appID string, changes []OIDCConfigChanges, ) (*OIDCConfigChangedEvent, error) { if len(changes) == 0 { return nil, zerrors.ThrowPreconditionFailed(nil, "OIDC-i8idç", "Errors.NoChangesFound") } changeEvent := &OIDCConfigChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, OIDCConfigChangedType, ), AppID: appID, } for _, change := range changes { change(changeEvent) } return changeEvent, nil } type OIDCConfigChanges func(event *OIDCConfigChangedEvent) func ChangeVersion(version domain.OIDCVersion) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.Version = &version } } func ChangeRedirectURIs(uris []string) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.RedirectUris = &uris } } func ChangeResponseTypes(responseTypes []domain.OIDCResponseType) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.ResponseTypes = &responseTypes } } func ChangeGrantTypes(grantTypes []domain.OIDCGrantType) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.GrantTypes = &grantTypes } } func ChangeApplicationType(appType domain.OIDCApplicationType) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.ApplicationType = &appType } } func ChangeAuthMethodType(authMethodType domain.OIDCAuthMethodType) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.AuthMethodType = &authMethodType } } func ChangePostLogoutRedirectURIs(logoutRedirects []string) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.PostLogoutRedirectUris = &logoutRedirects } } func ChangeDevMode(devMode bool) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.DevMode = &devMode } } func ChangeAccessTokenType(accessTokenType domain.OIDCTokenType) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.AccessTokenType = &accessTokenType } } func ChangeAccessTokenRoleAssertion(accessTokenRoleAssertion bool) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.AccessTokenRoleAssertion = &accessTokenRoleAssertion } } func ChangeIDTokenRoleAssertion(idTokenRoleAssertion bool) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.IDTokenRoleAssertion = &idTokenRoleAssertion } } func ChangeIDTokenUserinfoAssertion(idTokenUserinfoAssertion bool) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.IDTokenUserinfoAssertion = &idTokenUserinfoAssertion } } func ChangeClockSkew(clockSkew time.Duration) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.ClockSkew = &clockSkew } } func ChangeAdditionalOrigins(additionalOrigins []string) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.AdditionalOrigins = &additionalOrigins } } func ChangeSkipNativeAppSuccessPage(skipNativeAppSuccessPage bool) func(event *OIDCConfigChangedEvent) { return func(e *OIDCConfigChangedEvent) { e.SkipNativeAppSuccessPage = &skipNativeAppSuccessPage } } func OIDCConfigChangedEventMapper(event eventstore.Event) (eventstore.Event, error) { e := &OIDCConfigChangedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := event.Unmarshal(e) if err != nil { return nil, zerrors.ThrowInternal(err, "OIDC-BFd15", "unable to unmarshal oidc config") } return e, nil } type OIDCConfigSecretChangedEvent struct { eventstore.BaseEvent `json:"-"` AppID string `json:"appId"` ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` } func (e *OIDCConfigSecretChangedEvent) Payload() interface{} { return e } func (e *OIDCConfigSecretChangedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { return nil } func NewOIDCConfigSecretChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, appID string, clientSecret *crypto.CryptoValue, ) *OIDCConfigSecretChangedEvent { return &OIDCConfigSecretChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, OIDCConfigSecretChangedType, ), AppID: appID, ClientSecret: clientSecret, } } func OIDCConfigSecretChangedEventMapper(event eventstore.Event) (eventstore.Event, error) { e := &OIDCConfigSecretChangedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := event.Unmarshal(e) if err != nil { return nil, zerrors.ThrowInternal(err, "OIDC-M893d", "unable to unmarshal oidc config") } return e, nil } type OIDCConfigSecretCheckSucceededEvent struct { eventstore.BaseEvent `json:"-"` AppID string `json:"appId"` } func (e *OIDCConfigSecretCheckSucceededEvent) Payload() interface{} { return e } func (e *OIDCConfigSecretCheckSucceededEvent) UniqueConstraints() []*eventstore.UniqueConstraint { return nil } func NewOIDCConfigSecretCheckSucceededEvent( ctx context.Context, aggregate *eventstore.Aggregate, appID string, ) *OIDCConfigSecretCheckSucceededEvent { return &OIDCConfigSecretCheckSucceededEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, OIDCClientSecretCheckSucceededType, ), AppID: appID, } } func OIDCConfigSecretCheckSucceededEventMapper(event eventstore.Event) (eventstore.Event, error) { e := &OIDCConfigSecretCheckSucceededEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := event.Unmarshal(e) if err != nil { return nil, zerrors.ThrowInternal(err, "OIDC-837gV", "unable to unmarshal oidc config") } return e, nil } type OIDCConfigSecretCheckFailedEvent struct { eventstore.BaseEvent `json:"-"` AppID string `json:"appId"` } func (e *OIDCConfigSecretCheckFailedEvent) Payload() interface{} { return e } func (e *OIDCConfigSecretCheckFailedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { return nil } func NewOIDCConfigSecretCheckFailedEvent( ctx context.Context, aggregate *eventstore.Aggregate, appID string, ) *OIDCConfigSecretCheckFailedEvent { return &OIDCConfigSecretCheckFailedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, OIDCClientSecretCheckFailedType, ), AppID: appID, } } func OIDCConfigSecretCheckFailedEventMapper(event eventstore.Event) (eventstore.Event, error) { e := &OIDCConfigSecretCheckFailedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := event.Unmarshal(e) if err != nil { return nil, zerrors.ThrowInternal(err, "OIDC-987g%", "unable to unmarshal oidc config") } return e, nil }