diff --git a/backend/v3/domain/id_provider.go b/backend/v3/domain/id_provider.go index 5ef8dcdf5e..1e1de76924 100644 --- a/backend/v3/domain/id_provider.go +++ b/backend/v3/domain/id_provider.go @@ -35,6 +35,15 @@ const ( IDPStateInactive ) +//go:generate enumer -type IDPAutoLinkingOption -transform lower -trimprefix IDPAutoLinkingOption +type IDPAutoLinkingOption uint8 + +const ( + IDPAutoLinkingOptionUnspecified IDPAutoLinkingOption = iota + IDPAutoLinkingOptionUserName + IDPAutoLinkingOptionEmail +) + type OIDCMappingField int8 const ( @@ -57,8 +66,8 @@ type IdentityProvider struct { AllowAutoCreation bool `json:"allowAutoCreation,omitempty" db:"allow_auto_creation"` AllowAutoUpdate bool `json:"allowAutoUpdate,omitempty" db:"allow_auto_update"` AllowLinking bool `json:"allowLinking,omitempty" db:"allow_linking"` - AllowAutoLinking bool `json:"allowAutoLinking,omitempty" db:"allow_auto_linking"` - StylingType int16 `json:"stylingType,omitempty" db:"styling_type"` + AllowAutoLinking string `json:"allowAutoLinking,omitempty" db:"allow_auto_linking"` + StylingType *int16 `json:"stylingType,omitempty" db:"styling_type"` Payload *string `json:"payload,omitempty" db:"payload"` CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"` UpdatedAt time.Time `json:"updatedAt,omitempty" db:"updated_at"` @@ -74,6 +83,8 @@ type OIDC struct { Scopes []string `json:"scopes,omitempty"` IDPDisplayNameMapping OIDCMappingField `json:"IDPDisplayNameMapping,omitempty"` UserNameMapping OIDCMappingField `json:"usernameMapping,omitempty"` + IsIDTokenMapping bool `json:"idTokenMapping,omitempty"` + UsePKCE bool `json:"usePKCE,omitempty"` } type IDPOIDC struct { @@ -94,6 +105,24 @@ type IDPJWT struct { JWT } +type OAuth struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` + ClientID string `json:"clientId,omitempty"` + ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` + AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"` + TokenEndpoint string `json:"tokenEndpoint,omitempty"` + UserEndpoint string `json:"userEndpoint,omitempty"` + Scopes []string `json:"scopes,omitempty"` + IDAttribute string `json:"idAttribute,omitempty"` + UsePKCE bool `json:"usePKCE,omitempty"` +} + +type IDPOAuth struct { + *IdentityProvider + OAuth +} + // IDPIdentifierCondition is used to help specify a single identity_provider, // it will either be used as the identity_provider ID or identity_provider name, // as identity_provider can be identified either using (instanceID + OrgID + ID) OR (instanceID + OrgID + name) @@ -132,7 +161,7 @@ type idProviderConditions interface { AllowAutoCreationCondition(allow bool) database.Condition AllowAutoUpdateCondition(allow bool) database.Condition AllowLinkingCondition(allow bool) database.Condition - AllowAutoLinkingCondition(allow bool) database.Condition + AllowAutoLinkingCondition(linkingType IDPAutoLinkingOption) database.Condition StylingTypeCondition(style int16) database.Condition PayloadCondition(payload string) database.Condition } @@ -164,4 +193,6 @@ type IDProviderRepository interface { GetOIDC(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPOIDC, error) GetJWT(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPJWT, error) + + GetOAuth(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPOAuth, error) } diff --git a/backend/v3/domain/idpautolinkingoption_enumer.go b/backend/v3/domain/idpautolinkingoption_enumer.go new file mode 100644 index 0000000000..8984ea62e5 --- /dev/null +++ b/backend/v3/domain/idpautolinkingoption_enumer.go @@ -0,0 +1,82 @@ +// Code generated by "enumer -type IDPAutoLinkingOption -transform lower -trimprefix IDPAutoLinkingOption"; DO NOT EDIT. + +package domain + +import ( + "fmt" + "strings" +) + +const _IDPAutoLinkingOptionName = "unspecifiedusernameemail" + +var _IDPAutoLinkingOptionIndex = [...]uint8{0, 11, 19, 24} + +const _IDPAutoLinkingOptionLowerName = "unspecifiedusernameemail" + +func (i IDPAutoLinkingOption) String() string { + if i >= IDPAutoLinkingOption(len(_IDPAutoLinkingOptionIndex)-1) { + return fmt.Sprintf("IDPAutoLinkingOption(%d)", i) + } + return _IDPAutoLinkingOptionName[_IDPAutoLinkingOptionIndex[i]:_IDPAutoLinkingOptionIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _IDPAutoLinkingOptionNoOp() { + var x [1]struct{} + _ = x[IDPAutoLinkingOptionUnspecified-(0)] + _ = x[IDPAutoLinkingOptionUserName-(1)] + _ = x[IDPAutoLinkingOptionEmail-(2)] +} + +var _IDPAutoLinkingOptionValues = []IDPAutoLinkingOption{IDPAutoLinkingOptionUnspecified, IDPAutoLinkingOptionUserName, IDPAutoLinkingOptionEmail} + +var _IDPAutoLinkingOptionNameToValueMap = map[string]IDPAutoLinkingOption{ + _IDPAutoLinkingOptionName[0:11]: IDPAutoLinkingOptionUnspecified, + _IDPAutoLinkingOptionLowerName[0:11]: IDPAutoLinkingOptionUnspecified, + _IDPAutoLinkingOptionName[11:19]: IDPAutoLinkingOptionUserName, + _IDPAutoLinkingOptionLowerName[11:19]: IDPAutoLinkingOptionUserName, + _IDPAutoLinkingOptionName[19:24]: IDPAutoLinkingOptionEmail, + _IDPAutoLinkingOptionLowerName[19:24]: IDPAutoLinkingOptionEmail, +} + +var _IDPAutoLinkingOptionNames = []string{ + _IDPAutoLinkingOptionName[0:11], + _IDPAutoLinkingOptionName[11:19], + _IDPAutoLinkingOptionName[19:24], +} + +// IDPAutoLinkingOptionString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func IDPAutoLinkingOptionString(s string) (IDPAutoLinkingOption, error) { + if val, ok := _IDPAutoLinkingOptionNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _IDPAutoLinkingOptionNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to IDPAutoLinkingOption values", s) +} + +// IDPAutoLinkingOptionValues returns all values of the enum +func IDPAutoLinkingOptionValues() []IDPAutoLinkingOption { + return _IDPAutoLinkingOptionValues +} + +// IDPAutoLinkingOptionStrings returns a slice of all String values of the enum +func IDPAutoLinkingOptionStrings() []string { + strs := make([]string, len(_IDPAutoLinkingOptionNames)) + copy(strs, _IDPAutoLinkingOptionNames) + return strs +} + +// IsAIDPAutoLinkingOption returns "true" if the value is listed in the enum definition. "false" otherwise +func (i IDPAutoLinkingOption) IsAIDPAutoLinkingOption() bool { + for _, v := range _IDPAutoLinkingOptionValues { + if i == v { + return true + } + } + return false +} diff --git a/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/down.sql b/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/down.sql index 0831a6ca4f..5f3c655173 100644 --- a/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/down.sql +++ b/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/down.sql @@ -1,3 +1,4 @@ DROP TABLE zitadel.identity_providers; DROP Type zitadel.idp_state; DROP Type zitadel.idp_type; +DROP Type zitadel.idp_auto_linking_option; diff --git a/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/up.sql b/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/up.sql index 869abd97cd..35d2fa4acc 100644 --- a/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/up.sql +++ b/backend/v3/storage/database/dialect/postgres/migration/003_identity_providers_table/up.sql @@ -15,6 +15,12 @@ CREATE TYPE zitadel.idp_type AS ENUM ( 'apple' ); +CREATE TYPE zitadel.idp_auto_linking_option AS ENUM ( + 'unspecified', + 'username', + 'email' +); + CREATE TABLE zitadel.identity_providers ( instance_id TEXT NOT NULL , org_id TEXT @@ -27,7 +33,7 @@ CREATE TABLE zitadel.identity_providers ( , allow_auto_creation BOOLEAN NOT NULL DEFAULT TRUE , allow_auto_update BOOLEAN NOT NULL DEFAULT TRUE , allow_linking BOOLEAN NOT NULL DEFAULT TRUE - , allow_auto_linking BOOLEAN NOT NULL DEFAULT TRUE + , allow_auto_linking zitadel.idp_auto_linking_option NOT NULL DEFAULT 'unspecified' , styling_type SMALLINT , payload JSONB diff --git a/backend/v3/storage/database/events_testing/id_provider_test.go b/backend/v3/storage/database/events_testing/id_provider_test.go index 8d9cdf0f1e..f80825a4e6 100644 --- a/backend/v3/storage/database/events_testing/id_provider_test.go +++ b/backend/v3/storage/database/events_testing/id_provider_test.go @@ -22,7 +22,7 @@ import ( func TestServer_TestIDProviderReduces(t *testing.T) { instanceID := Instance.ID() - t.Run("test idp add reduces", func(t *testing.T) { + t.Run("test iam idp add reduces", func(t *testing.T) { name := gofakeit.Name() beforeCreate := time.Now() @@ -57,13 +57,13 @@ func TestServer_TestIDProviderReduces(t *testing.T) { assert.Equal(t, instanceID, idp.InstanceID) assert.Equal(t, domain.IDPStateActive.String(), idp.State) assert.Equal(t, true, idp.AutoRegister) - assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), idp.StylingType) + assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *idp.StylingType) assert.WithinRange(t, idp.UpdatedAt, beforeCreate, afterCreate) assert.WithinRange(t, idp.CreatedAt, beforeCreate, afterCreate) }, retryDuration, tick) }) - t.Run("test idp update reduces", func(t *testing.T) { + t.Run("test iam idp update reduces", func(t *testing.T) { name := gofakeit.Name() addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ @@ -106,12 +106,12 @@ func TestServer_TestIDProviderReduces(t *testing.T) { assert.Equal(t, addOIDC.IdpId, idp.ID) assert.Equal(t, name, idp.Name) assert.Equal(t, false, idp.AutoRegister) - assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED), idp.StylingType) + assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED), *idp.StylingType) assert.WithinRange(t, idp.UpdatedAt, beforeCreate, afterCreate) }, retryDuration, tick) }) - t.Run("test idp deactivate reduces", func(t *testing.T) { + t.Run("test iam idp deactivate reduces", func(t *testing.T) { name := gofakeit.Name() addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ @@ -153,7 +153,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }, retryDuration, tick) }) - t.Run("test idp reactivate reduces", func(t *testing.T) { + t.Run("test iam idp reactivate reduces", func(t *testing.T) { name := gofakeit.Name() addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ @@ -214,7 +214,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }, retryDuration, tick) }) - t.Run("test idp remove reduces", func(t *testing.T) { + t.Run("test iam idp remove reduces", func(t *testing.T) { name := gofakeit.Name() // add idp @@ -252,7 +252,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }, retryDuration, tick) }) - t.Run("test idp oidc addded reduces", func(t *testing.T) { + t.Run("test iam idp oidc addded reduces", func(t *testing.T) { name := gofakeit.Name() // add oidc @@ -295,7 +295,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }, retryDuration, tick) }) - t.Run("test idp oidc changed reduces", func(t *testing.T) { + t.Run("test iam idp oidc changed reduces", func(t *testing.T) { name := gofakeit.Name() // add oidc @@ -373,7 +373,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }, retryDuration, tick) }) - t.Run("test idp jwt addded reduces", func(t *testing.T) { + t.Run("test iam idp jwt addded reduces", func(t *testing.T) { name := gofakeit.Name() // add jwt @@ -399,7 +399,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { ) require.NoError(t, err) - // event org.idp.jwt.config.added + // event iam.idp.jwt.config.added // idp assert.Equal(t, addJWT.IdpId, jwt.ID) assert.Equal(t, domain.IDPTypeJWT.String(), jwt.Type) @@ -413,7 +413,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }, retryDuration, tick) }) - t.Run("test idp jwt changed reduces", func(t *testing.T) { + t.Run("test iam idp jwt changed reduces", func(t *testing.T) { name := gofakeit.Name() // add jwt @@ -469,7 +469,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { ) require.NoError(t, err) - // event org.idp.jwt.config.changed + // event iam.idp.jwt.config.changed // idp assert.Equal(t, addJWT.IdpId, updateJWT.ID) assert.Equal(t, domain.IDPTypeJWT.String(), updateJWT.Type) @@ -482,4 +482,295 @@ func TestServer_TestIDProviderReduces(t *testing.T) { assert.Equal(t, "new_keyEndpoint", updateJWT.KeysEndpoint) }, retryDuration, tick) }) + + t.Run("test instance idp oauth added reduces", func(t *testing.T) { + name := gofakeit.Name() + + // add oauth + beforeCreate := time.Now().Add(-1 * time.Second) + addOAuth, err := AdminClient.AddGenericOAuthProvider(CTX, &admin.AddGenericOAuthProviderRequest{ + Name: name, + ClientId: "clientId", + ClientSecret: "clientSecret", + AuthorizationEndpoint: "authoizationEndpoint", + TokenEndpoint: "tokenEndpoint", + UserEndpoint: "userEndpoint", + Scopes: []string{"scope"}, + IdAttribute: "idAttribute", + ProviderOptions: &idp_grpc.Options{ + IsLinkingAllowed: false, + IsCreationAllowed: false, + IsAutoCreation: false, + IsAutoUpdate: false, + AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL, + }, + UsePkce: false, + }) + afterCreate := time.Now() + require.NoError(t, err) + + idpRepo := repository.IDProviderRepository(pool) + + // check values for oauth + var oauth *domain.IDPOAuth + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + oauth, err = idpRepo.GetOAuth(CTX, idpRepo.IDCondition(addOAuth.Id), instanceID, nil) + require.NoError(t, err) + + // event instance.idp.oauth.added + // idp + assert.Equal(t, addOAuth.Id, oauth.IdentityProvider.ID) + assert.Equal(t, domain.IDPTypeOAuth.String(), oauth.Type) + + // oauth + assert.Equal(t, addOAuth.Id, oauth.IdentityProvider.ID) + assert.Equal(t, "clientId", oauth.ClientID) + assert.NotNil(t, oauth.ClientSecret) + assert.Equal(t, "authoizationEndpoint", oauth.AuthorizationEndpoint) + assert.Equal(t, "authoizationEndpoint", oauth.AuthorizationEndpoint) + assert.Equal(t, "tokenEndpoint", oauth.TokenEndpoint) + assert.Equal(t, "userEndpoint", oauth.UserEndpoint) + assert.Equal(t, "userEndpoint", oauth.UserEndpoint) + assert.Equal(t, []string{"scope"}, oauth.Scopes) + assert.Equal(t, false, oauth.AllowLinking) + assert.Equal(t, false, oauth.AllowCreation) + assert.Equal(t, false, oauth.AllowAutoUpdate) + assert.Equal(t, domain.IDPAutoLinkingOptionEmail.String(), oauth.AllowAutoLinking) + assert.Equal(t, false, oauth.UsePKCE) + assert.WithinRange(t, oauth.CreatedAt, beforeCreate, afterCreate) + assert.WithinRange(t, oauth.UpdatedAt, beforeCreate, afterCreate) + }, retryDuration, tick) + }) + + t.Run("test instanceidp oauth changed reduces", func(t *testing.T) { + name := gofakeit.Name() + + // add oauth + addOAuth, err := AdminClient.AddGenericOAuthProvider(CTX, &admin.AddGenericOAuthProviderRequest{ + Name: name, + ClientId: "clientId", + ClientSecret: "clientSecret", + AuthorizationEndpoint: "authoizationEndpoint", + TokenEndpoint: "tokenEndpoint", + UserEndpoint: "userEndpoint", + Scopes: []string{"scope"}, + IdAttribute: "idAttribute", + ProviderOptions: &idp_grpc.Options{ + IsLinkingAllowed: false, + IsCreationAllowed: false, + IsAutoCreation: false, + IsAutoUpdate: false, + AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL, + }, + UsePkce: false, + }) + require.NoError(t, err) + + idpRepo := repository.IDProviderRepository(pool) + + // check values for oauth + var oauth *domain.IDPOAuth + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + oauth, err = idpRepo.GetOAuth(CTX, idpRepo.IDCondition(addOAuth.Id), instanceID, nil) + require.NoError(t, err) + }, retryDuration, tick) + + name = "new_" + name + beforeCreate := time.Now() + _, err = AdminClient.UpdateGenericOAuthProvider(CTX, &admin.UpdateGenericOAuthProviderRequest{ + Id: addOAuth.Id, + Name: name, + ClientId: "new_clientId", + ClientSecret: "new_clientSecret", + AuthorizationEndpoint: "new_authoizationEndpoint", + TokenEndpoint: "new_tokenEndpoint", + UserEndpoint: "new_userEndpoint", + Scopes: []string{"new_scope"}, + IdAttribute: "new_idAttribute", + ProviderOptions: &idp_grpc.Options{ + IsLinkingAllowed: true, + IsCreationAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME, + }, + UsePkce: true, + }) + afterCreate := time.Now() + require.NoError(t, err) + + retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + updateOauth, err := idpRepo.GetOAuth(CTX, + idpRepo.IDCondition(addOAuth.Id), + instanceID, + nil, + ) + require.NoError(t, err) + + // event instance.idp.oauth.changed + // idp + assert.Equal(t, addOAuth.Id, oauth.IdentityProvider.ID) + assert.Equal(t, domain.IDPTypeOAuth.String(), oauth.Type) + + // oauth + assert.Equal(t, addOAuth.Id, updateOauth.IdentityProvider.ID) + assert.Equal(t, "new_clientId", updateOauth.ClientID) + assert.NotEqual(t, oauth.ClientSecret, updateOauth.ClientSecret) + assert.Equal(t, "new_authoizationEndpoint", updateOauth.AuthorizationEndpoint) + assert.Equal(t, "new_tokenEndpoint", updateOauth.TokenEndpoint) + assert.Equal(t, "new_userEndpoint", updateOauth.UserEndpoint) + assert.Equal(t, []string{"new_scope"}, updateOauth.Scopes) + assert.Equal(t, true, updateOauth.AllowLinking) + assert.Equal(t, true, updateOauth.AllowCreation) + assert.Equal(t, true, updateOauth.AllowAutoUpdate) + assert.Equal(t, domain.IDPAutoLinkingOptionUserName.String(), updateOauth.AllowAutoLinking) + assert.Equal(t, true, updateOauth.UsePKCE) + assert.WithinRange(t, updateOauth.UpdatedAt, beforeCreate, afterCreate) + }, retryDuration, tick) + }) + + t.Run("test instance idp oidc added reduces", func(t *testing.T) { + name := gofakeit.Name() + + // add oidc + beforeCreate := time.Now().Add(-1 * time.Second) + addOIDC, err := AdminClient.AddGenericOIDCProvider(CTX, &admin.AddGenericOIDCProviderRequest{ + Name: name, + ClientId: "clientId", + ClientSecret: "clientSecret", + Scopes: []string{"scope"}, + Issuer: "issuer", + ProviderOptions: &idp_grpc.Options{ + IsLinkingAllowed: false, + IsCreationAllowed: false, + IsAutoCreation: false, + IsAutoUpdate: false, + AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL, + }, + IsIdTokenMapping: false, + UsePkce: false, + }) + afterCreate := time.Now() + require.NoError(t, err) + + idpRepo := repository.IDProviderRepository(pool) + + // check values for oidc + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + oidc, err := idpRepo.GetOIDC(CTX, idpRepo.IDCondition(addOIDC.Id), instanceID, nil) + require.NoError(t, err) + + // event instance.idp.oidc added + // idp + assert.Equal(t, addOIDC.Id, oidc.ID) + assert.Equal(t, domain.IDPTypeOIDC.String(), oidc.Type) + + // oidc + assert.Equal(t, addOIDC.Id, oidc.ID) + assert.Equal(t, "clientId", oidc.ClientID) + // assert.NotNil(t, oidc.ClientSecret) + // assert.Equal(t, "authoizationEndpoint", oidc.AuthorizationEndpoint) + // assert.Equal(t, "tokenEndpoint", oidc.TokenEndpoint) + // assert.Equal(t, "userEndpoint", oidc.UserEndpoint) + // assert.Equal(t, "userEndpoint", oidc.UserEndpoint) + assert.Equal(t, []string{"scope"}, oidc.Scopes) + assert.Equal(t, "issuer", oidc.Issuer) + assert.Equal(t, false, oidc.IsIDTokenMapping) + assert.Equal(t, false, oidc.AllowLinking) + assert.Equal(t, false, oidc.AllowCreation) + assert.Equal(t, false, oidc.AllowAutoUpdate) + assert.Equal(t, domain.IDPAutoLinkingOptionEmail.String(), oidc.AllowAutoLinking) + assert.Equal(t, false, oidc.UsePKCE) + assert.WithinRange(t, oidc.CreatedAt, beforeCreate, afterCreate) + assert.WithinRange(t, oidc.UpdatedAt, beforeCreate, afterCreate) + }, retryDuration, tick) + }) + + t.Run("test instanceidp oidc changed reduces", func(t *testing.T) { + name := gofakeit.Name() + + addOIDC, err := AdminClient.AddGenericOIDCProvider(CTX, &admin.AddGenericOIDCProviderRequest{ + Name: name, + ClientId: "clientId", + ClientSecret: "clientSecret", + Scopes: []string{"scope"}, + Issuer: "issuer", + ProviderOptions: &idp_grpc.Options{ + IsLinkingAllowed: false, + IsCreationAllowed: false, + IsAutoCreation: false, + IsAutoUpdate: false, + AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL, + }, + IsIdTokenMapping: false, + UsePkce: false, + }) + require.NoError(t, err) + + idpRepo := repository.IDProviderRepository(pool) + + // check values for oidc + var oidc *domain.IDPOIDC + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + oidc, err = idpRepo.GetOIDC(CTX, idpRepo.IDCondition(addOIDC.Id), instanceID, nil) + require.NoError(t, err) + }, retryDuration, tick) + + name = "new_" + name + beforeCreate := time.Now() + _, err = AdminClient.UpdateGenericOIDCProvider(CTX, &admin.UpdateGenericOIDCProviderRequest{ + Id: addOIDC.Id, + Name: name, + Issuer: "new_issuer", + ClientId: "new_clientId", + ClientSecret: "new_clientSecret", + Scopes: []string{"new_scope"}, + ProviderOptions: &idp_grpc.Options{ + IsLinkingAllowed: true, + IsCreationAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME, + }, + IsIdTokenMapping: true, + UsePkce: true, + }) + afterCreate := time.Now() + require.NoError(t, err) + + retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + updateOIDC, err := idpRepo.GetOIDC(CTX, + idpRepo.IDCondition(addOIDC.Id), + instanceID, + nil, + ) + require.NoError(t, err) + + // event instance.idp.oidc.changed + // idp + assert.Equal(t, addOIDC.Id, oidc.ID) + assert.Equal(t, domain.IDPTypeOIDC.String(), oidc.Type) + + // oidc + assert.Equal(t, addOIDC.Id, updateOIDC.ID) + assert.Equal(t, "new_clientId", updateOIDC.ClientID) + assert.NotEqual(t, oidc.ClientSecret, updateOIDC.ClientSecret) + // assert.Equal(t, "new_authoizationEndpoint", updateOIDC.AuthorizationEndpoint) + // assert.Equal(t, "new_tokenEndpoint", updateOIDC.TokenEndpoint) + assert.Equal(t, []string{"new_scope"}, updateOIDC.Scopes) + assert.Equal(t, true, updateOIDC.IsIDTokenMapping) + assert.Equal(t, true, updateOIDC.AllowLinking) + assert.Equal(t, true, updateOIDC.AllowCreation) + assert.Equal(t, true, updateOIDC.AllowAutoUpdate) + assert.Equal(t, domain.IDPAutoLinkingOptionUserName.String(), updateOIDC.AllowAutoLinking) + assert.Equal(t, true, updateOIDC.UsePKCE) + assert.WithinRange(t, updateOIDC.UpdatedAt, beforeCreate, afterCreate) + }, retryDuration, tick) + }) } diff --git a/backend/v3/storage/database/repository/id_provider.go b/backend/v3/storage/database/repository/id_provider.go index be5560de09..5671e19d87 100644 --- a/backend/v3/storage/database/repository/id_provider.go +++ b/backend/v3/storage/database/repository/id_provider.go @@ -163,6 +163,28 @@ func (i *idProvider) GetJWT(ctx context.Context, id domain.IDPIdentifierConditio return idpJWT, nil } +func (i *idProvider) GetOAuth(ctx context.Context, id domain.IDPIdentifierCondition, instnaceID string, orgID *string) (*domain.IDPOAuth, error) { + idpOAuth := &domain.IDPOAuth{} + var err error + + idpOAuth.IdentityProvider, err = i.Get(ctx, id, instnaceID, orgID) + if err != nil { + return nil, err + } + + if idpOAuth.Type != domain.IDPTypeOAuth.String() { + // TODO + return nil, errors.New("WRONG TYPE") + } + + err = json.Unmarshal([]byte(*idpOAuth.Payload), idpOAuth) + if err != nil { + return nil, err + } + + return idpOAuth, nil +} + // ------------------------------------------------------------- // columns // ------------------------------------------------------------- @@ -282,8 +304,8 @@ func (i idProvider) AllowLinkingCondition(allow bool) database.Condition { return database.NewBooleanCondition(i.AllowLinkingColumn(), allow) } -func (i idProvider) AllowAutoLinkingCondition(allow bool) database.Condition { - return database.NewBooleanCondition(i.AllowAutoLinkingColumn(), allow) +func (i idProvider) AllowAutoLinkingCondition(linkingType domain.IDPAutoLinkingOption) database.Condition { + return database.NewTextCondition(i.AllowAutoLinkingColumn(), database.TextOperationEqual, linkingType.String()) } func (i idProvider) StylingTypeCondition(style int16) database.Condition { diff --git a/go.mod b/go.mod index 2cb3da84f1..57b3399cb0 100644 --- a/go.mod +++ b/go.mod @@ -95,12 +95,12 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.35.0 go.opentelemetry.io/otel/trace v1.35.0 go.uber.org/mock v0.5.2 - golang.org/x/crypto v0.38.0 + golang.org/x/crypto v0.40.0 golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 - golang.org/x/net v0.40.0 + golang.org/x/net v0.42.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.14.0 - golang.org/x/text v0.25.0 + golang.org/x/sync v0.16.0 + golang.org/x/text v0.27.0 google.golang.org/api v0.233.0 google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9 google.golang.org/grpc v1.72.1 @@ -125,7 +125,6 @@ require ( github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect github.com/crewjam/httperr v0.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dmarkham/enumer v1.5.11 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -153,7 +152,6 @@ require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pascaldekloe/name v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect @@ -173,9 +171,7 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.24.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.33.0 // indirect google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect ) @@ -247,7 +243,7 @@ require ( github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect - golang.org/x/sys v0.33.0 + golang.org/x/sys v0.34.0 gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.11 // indirect diff --git a/go.sum b/go.sum index 5c4851993f..ecf3bd3c3b 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,6 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dmarkham/enumer v1.5.11 h1:quorLCaEfzjJ23Pf7PB9lyyaHseh91YfTM/sAD/4Mbo= -github.com/dmarkham/enumer v1.5.11/go.mod h1:yixql+kDDQRYqcuBM2n9Vlt7NoT9ixgXhaXry8vmRg8= github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c h1:mxWGS0YyquJ/ikZOjSrRjjFIbUqIP9ojyYQ+QZTU3Rg= github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0 h1:fuHXpEVTTk7TilRdfGRLHpiTD6tnT0ihEowCfWjlFvw= @@ -630,8 +628,6 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/name v1.0.0 h1:n7LKFgHixETzxpRv2R77YgPUFo85QHGZKrdaYm7eY5U= -github.com/pascaldekloe/name v1.0.0/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM= github.com/pashagolub/pgxmock/v4 v4.7.0 h1:de2ORuFYyjwOQR7NBm57+321RnZxpYiuUjsmqRiqgh8= github.com/pashagolub/pgxmock/v4 v4.7.0/go.mod h1:9L57pC193h2aKRHVyiiE817avasIPZnPwPlw3JczWvM= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -897,8 +893,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= @@ -919,8 +915,6 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -952,8 +946,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -967,8 +961,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1004,15 +998,15 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= @@ -1037,8 +1031,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/query/projection/idp_template_relational.go b/internal/query/projection/idp_template_relational.go index 2e0576176e..26f763321c 100644 --- a/internal/query/projection/idp_template_relational.go +++ b/internal/query/projection/idp_template_relational.go @@ -2,13 +2,27 @@ package projection import ( "context" + "encoding/json" + "fmt" "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres" "github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/backend/v3/domain" + "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler/v2" + "github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +const ( + IDPRelationalAllowCreationCol = "allow_creation" + IDPRelationalAllowLinkingCol = "allow_linking" + IDPRelationalAllowAutoCreationCol = "allow_auto_creation" + IDPRelationalAllowAutoUpdateCol = "allow_auto_update" + IDPRelationalAllowAutoLinkingCol = "allow_auto_linking" ) type idpTemplateRelationalProjection struct { @@ -25,7 +39,6 @@ func newIDPTemplateRelationalProjection(ctx context.Context, config handler.Conf func (*idpTemplateRelationalProjection) Name() string { return IDPRelationalTable - // return IDPTemplateTable } func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer { @@ -35,20 +48,20 @@ func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer EventReducers: []handler.EventReducer{ { Event: instance.OAuthIDPAddedEventType, - Reduce: p.reduceOAuthIDPAdded, + Reduce: p.reduceOAuthIDPRelationalAdded, + }, + { + Event: instance.OAuthIDPChangedEventType, + Reduce: p.reduceOAuthIDPRelationalChanged, + }, + { + Event: instance.OIDCIDPAddedEventType, + Reduce: p.reduceOIDCIDPRelationalAdded, + }, + { + Event: instance.OIDCIDPChangedEventType, + Reduce: p.reduceOIDCIDPRelationalChanged, }, - // { - // Event: instance.OAuthIDPChangedEventType, - // Reduce: p.reduceOAuthIDPChanged, - // }, - // { - // Event: instance.OIDCIDPAddedEventType, - // Reduce: p.reduceOIDCIDPAdded, - // }, - // { - // Event: instance.OIDCIDPChangedEventType, - // Reduce: p.reduceOIDCIDPChanged, - // }, // { // Event: instance.OIDCIDPMigratedAzureADEventType, // Reduce: p.reduceOIDCIDPMigratedAzureAD, @@ -323,191 +336,218 @@ func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer } } -// func (p *idpTemplateProjection) reduceOAuthIDPAdded(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idp.OAuthIDPAddedEvent -// var idpOwnerType domain.IdentityProviderType -// switch e := event.(type) { -// case *org.OAuthIDPAddedEvent: -// idpEvent = e.OAuthIDPAddedEvent -// idpOwnerType = domain.IdentityProviderTypeOrg -// case *instance.OAuthIDPAddedEvent: -// idpEvent = e.OAuthIDPAddedEvent -// idpOwnerType = domain.IdentityProviderTypeSystem -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-ap9ihb", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPAddedEventType, instance.OAuthIDPAddedEventType}) -// } +func (p *idpTemplateRelationalProjection) reduceOAuthIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) { + // var idpEvent idp.OAuthIDPAddedEvent + // var idpOwnerType domain.IdentityProviderType + // switch e := event.(type) { + // case *org.OAuthIDPAddedEvent: + // idpEvent = e.OAuthIDPAddedEvent + // idpOwnerType = domain.IdentityProviderTypeOrg + // case *instance.OAuthIDPAddedEvent: + // idpEvent = e.OAuthIDPAddedEvent + // idpOwnerType = domain.IdentityProviderTypeSystem + // default: + // } -// return handler.NewMultiStatement( -// &idpEvent, -// handler.AddCreateStatement( -// []handler.Column{ -// handler.NewCol(IDPTemplateIDCol, idpEvent.ID), -// handler.NewCol(IDPTemplateCreationDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()), -// handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner), -// handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), -// handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive), -// handler.NewCol(IDPTemplateNameCol, idpEvent.Name), -// handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType), -// handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeOAuth), -// handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed), -// handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed), -// handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation), -// handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate), -// handler.NewCol(IDPTemplateAutoLinkingCol, idpEvent.AutoLinkingOption), -// }, -// ), -// handler.AddCreateStatement( -// []handler.Column{ -// handler.NewCol(OAuthIDCol, idpEvent.ID), -// handler.NewCol(OAuthInstanceIDCol, idpEvent.Aggregate().InstanceID), -// handler.NewCol(OAuthClientIDCol, idpEvent.ClientID), -// handler.NewCol(OAuthClientSecretCol, idpEvent.ClientSecret), -// handler.NewCol(OAuthAuthorizationEndpointCol, idpEvent.AuthorizationEndpoint), -// handler.NewCol(OAuthTokenEndpointCol, idpEvent.TokenEndpoint), -// handler.NewCol(OAuthUserEndpointCol, idpEvent.UserEndpoint), -// handler.NewCol(OAuthScopesCol, database.TextArray[string](idpEvent.Scopes)), -// handler.NewCol(OAuthIDAttributeCol, idpEvent.IDAttribute), -// handler.NewCol(OAuthUsePKCECol, idpEvent.UsePKCE), -// }, -// handler.WithTableSuffix(IDPTemplateOAuthSuffix), -// ), -// ), nil -// } + e, ok := event.(*instance.OAuthIDPAddedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-ap9ihb", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPAddedEventType, instance.OAuthIDPAddedEventType}) + } -// func (p *idpTemplateProjection) reduceOAuthIDPChanged(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idp.OAuthIDPChangedEvent -// switch e := event.(type) { -// case *org.OAuthIDPChangedEvent: -// idpEvent = e.OAuthIDPChangedEvent -// case *instance.OAuthIDPChangedEvent: -// idpEvent = e.OAuthIDPChangedEvent -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPChangedEventType, instance.OAuthIDPChangedEventType}) -// } + oauth := domain.OAuth{ + ID: e.ID, + Name: e.Name, + ClientID: e.ClientID, + ClientSecret: e.ClientSecret, + AuthorizationEndpoint: e.AuthorizationEndpoint, + TokenEndpoint: e.TokenEndpoint, + UserEndpoint: e.UserEndpoint, + Scopes: e.Scopes, + IDAttribute: e.IDAttribute, + UsePKCE: e.UsePKCE, + } -// ops := make([]func(eventstore.Event) handler.Exec, 0, 2) -// ops = append(ops, -// handler.AddUpdateStatement( -// reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges), -// []handler.Condition{ -// handler.NewCond(IDPTemplateIDCol, idpEvent.ID), -// handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// ), -// ) -// oauthCols := reduceOAuthIDPChangedColumns(idpEvent) -// if len(oauthCols) > 0 { -// ops = append(ops, -// handler.AddUpdateStatement( -// oauthCols, -// []handler.Condition{ -// handler.NewCond(OAuthIDCol, idpEvent.ID), -// handler.NewCond(OAuthInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// handler.WithTableSuffix(IDPTemplateOAuthSuffix), -// ), -// ) -// } + payload, err := json.Marshal(oauth) + if err != nil { + return nil, err + } -// return handler.NewMultiStatement( -// &idpEvent, -// ops..., -// ), nil -// } + return handler.NewMultiStatement( + e, + handler.AddCreateStatement( + []handler.Column{ + handler.NewCol(IDPTemplateIDCol, e.ID), + handler.NewCol(IDPTemplateInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive.String()), + handler.NewCol(IDPTemplateNameCol, e.Name), + handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeOAuth.String()), + handler.NewCol(IDPRelationalAllowCreationCol, e.IsCreationAllowed), + handler.NewCol(IDPRelationalAllowLinkingCol, e.IsLinkingAllowed), + handler.NewCol(IDPRelationalAllowAutoCreationCol, e.IsAutoCreation), + handler.NewCol(IDPRelationalAllowAutoUpdateCol, e.IsAutoUpdate), + handler.NewCol(IDPRelationalAllowAutoLinkingCol, domain.IDPAutoLinkingOption(e.AutoLinkingOption).String()), + handler.NewCol(IDPRelationalPayloadCol, payload), + handler.NewCol(CreatedAt, e.CreationDate()), + }, + ), + ), nil +} -// func (p *idpTemplateProjection) reduceOIDCIDPAdded(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idp.OIDCIDPAddedEvent -// var idpOwnerType domain.IdentityProviderType -// switch e := event.(type) { -// case *org.OIDCIDPAddedEvent: -// idpEvent = e.OIDCIDPAddedEvent -// idpOwnerType = domain.IdentityProviderTypeOrg -// case *instance.OIDCIDPAddedEvent: -// idpEvent = e.OIDCIDPAddedEvent -// idpOwnerType = domain.IdentityProviderTypeSystem -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPAddedEventType, instance.OIDCIDPAddedEventType}) -// } +func (p *idpTemplateRelationalProjection) reduceOAuthIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) { + // var idpEvent idp.OAuthIDPChangedEvent + // switch e := event.(type) { + // case *org.OAuthIDPChangedEvent: + // idpEvent = e.OAuthIDPChangedEvent + // case *instance.OAuthIDPChangedEvent: + // idpEvent = e.OAuthIDPChangedEvent + // default: + // return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPChangedEventType, instance.OAuthIDPChangedEventType}) + // } -// return handler.NewMultiStatement( -// &idpEvent, -// handler.AddCreateStatement( -// []handler.Column{ -// handler.NewCol(IDPTemplateIDCol, idpEvent.ID), -// handler.NewCol(IDPTemplateCreationDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()), -// handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner), -// handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), -// handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive), -// handler.NewCol(IDPTemplateNameCol, idpEvent.Name), -// handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType), -// handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeOIDC), -// handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed), -// handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed), -// handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation), -// handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate), -// handler.NewCol(IDPTemplateAutoLinkingCol, idpEvent.AutoLinkingOption), -// }, -// ), -// handler.AddCreateStatement( -// []handler.Column{ -// handler.NewCol(OIDCIDCol, idpEvent.ID), -// handler.NewCol(OIDCInstanceIDCol, idpEvent.Aggregate().InstanceID), -// handler.NewCol(OIDCIssuerCol, idpEvent.Issuer), -// handler.NewCol(OIDCClientIDCol, idpEvent.ClientID), -// handler.NewCol(OIDCClientSecretCol, idpEvent.ClientSecret), -// handler.NewCol(OIDCScopesCol, database.TextArray[string](idpEvent.Scopes)), -// handler.NewCol(OIDCIDTokenMappingCol, idpEvent.IsIDTokenMapping), -// handler.NewCol(OIDCUsePKCECol, idpEvent.UsePKCE), -// }, -// handler.WithTableSuffix(IDPTemplateOIDCSuffix), -// ), -// ), nil -// } + e, ok := event.(*instance.OAuthIDPChangedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPChangedEventType, instance.OAuthIDPChangedEventType}) + } -// func (p *idpTemplateProjection) reduceOIDCIDPChanged(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idp.OIDCIDPChangedEvent -// switch e := event.(type) { -// case *org.OIDCIDPChangedEvent: -// idpEvent = e.OIDCIDPChangedEvent -// case *instance.OIDCIDPChangedEvent: -// idpEvent = e.OIDCIDPChangedEvent -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPChangedEventType, instance.OIDCIDPChangedEventType}) -// } + oauth, err := p.idpRepo.GetOAuth(context.Background(), p.idpRepo.IDCondition(e.ID), e.Agg.InstanceID, nil) + if err != nil { + return nil, err + } -// ops := make([]func(eventstore.Event) handler.Exec, 0, 2) -// ops = append(ops, -// handler.AddUpdateStatement( -// reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges), -// []handler.Condition{ -// handler.NewCond(IDPTemplateIDCol, idpEvent.ID), -// handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// ), -// ) -// oidcCols := reduceOIDCIDPChangedColumns(idpEvent) -// if len(oidcCols) > 0 { -// ops = append(ops, -// handler.AddUpdateStatement( -// oidcCols, -// []handler.Condition{ -// handler.NewCond(OIDCIDCol, idpEvent.ID), -// handler.NewCond(OIDCInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// handler.WithTableSuffix(IDPTemplateOIDCSuffix), -// ), -// ) -// } + columns := make([]handler.Column, 0, 7) + reduceIDPRelationalChangedTemplateColumns(e.Name, e.OptionChanges, &columns) -// return handler.NewMultiStatement( -// &idpEvent, -// ops..., -// ), nil -// } + payload := &oauth.OAuth + payloadChanged := reduceOAuthIDPRelationalChangedColumns(payload, &e.OAuthIDPChangedEvent) + if payloadChanged { + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } + columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payload)) + } + + return handler.NewMultiStatement( + e, + handler.AddUpdateStatement( + columns, + []handler.Condition{ + handler.NewCond(IDPTemplateIDCol, e.ID), + handler.NewCond(IDPTemplateInstanceIDCol, e.Aggregate().InstanceID), + }, + ), + ), nil +} + +func (p *idpTemplateRelationalProjection) reduceOIDCIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) { + // var idpEvent idp.OIDCIDPAddedEvent + // var idpOwnerType domain.IdentityProviderType + // switch e := event.(type) { + // case *org.OIDCIDPAddedEvent: + // idpEvent = e.OIDCIDPAddedEvent + // idpOwnerType = domain.IdentityProviderTypeOrg + // case *instance.OIDCIDPAddedEvent: + // idpEvent = e.OIDCIDPAddedEvent + // idpOwnerType = domain.IdentityProviderTypeSystem + // default: + // return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPAddedEventType, instance.OIDCIDPAddedEventType}) + // } + + e, ok := event.(*instance.OIDCIDPAddedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPAddedEventType, instance.OIDCIDPAddedEventType}) + } + + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } + + return handler.NewMultiStatement( + e, + handler.AddCreateStatement( + []handler.Column{ + handler.NewCol(IDPTemplateIDCol, e.ID), + handler.NewCol(CreatedAt, e.CreationDate()), + // handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()), + // handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()), + // handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner), + handler.NewCol(IDPTemplateInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive), + handler.NewCol(IDPTemplateNameCol, e.Name), + // handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType), + handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeOIDC.String()), + handler.NewCol(IDPRelationalAllowCreationCol, e.IsCreationAllowed), + handler.NewCol(IDPRelationalAllowLinkingCol, e.IsLinkingAllowed), + handler.NewCol(IDPRelationalAllowAutoCreationCol, e.IsAutoCreation), + handler.NewCol(IDPRelationalAllowAutoUpdateCol, e.IsAutoUpdate), + handler.NewCol(IDPRelationalAllowAutoLinkingCol, domain.IDPAutoLinkingOption(e.AutoLinkingOption).String()), + handler.NewCol(IDPRelationalPayloadCol, payload), + }, + ), + ), nil +} + +func (p *idpTemplateRelationalProjection) reduceOIDCIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) { + // var idpEvent idp.OIDCIDPChangedEvent + // switch e := event.(type) { + // case *org.OIDCIDPChangedEvent: + // idpEvent = e.OIDCIDPChangedEvent + // case *instance.OIDCIDPChangedEvent: + // idpEvent = e.OIDCIDPChangedEvent + // default: + // return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPChangedEventType, instance.OIDCIDPChangedEventType}) + // } + + e, ok := event.(*instance.OIDCIDPChangedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPChangedEventType, instance.OIDCIDPChangedEventType}) + } + + oidc, err := p.idpRepo.GetOIDC(context.Background(), p.idpRepo.IDCondition(e.ID), e.Agg.InstanceID, nil) + if err != nil { + return nil, err + } + + columns := make([]handler.Column, 0, 7) + reduceIDPRelationalChangedTemplateColumns(e.Name, e.OptionChanges, &columns) + + // ops := make([]func(eventstore.Event) handler.Exec, 0, 2) + // ops = append(ops, + // handler.AddUpdateStatement( + // reduceIDPRelationalChangedTemplateColumns(e.Name, e.OptionChanges), + // []handler.Condition{ + // handler.NewCond(IDPTemplateIDCol, e.ID), + // handler.NewCond(IDPTemplateInstanceIDCol, e.Aggregate().InstanceID), + // }, + // ), + // ) + fmt.Println("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> OIDC CHANGED") + payload := &oidc.OIDC + payloadChanged := reduceOIDCIDPRelationalChangedColumns(payload, &e.OIDCIDPChangedEvent) + if payloadChanged { + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } + columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payload)) + } + + // return handler.NewMultiStatement( + // &e, + // ops..., + // ), nil + return handler.NewMultiStatement( + e, + handler.AddUpdateStatement( + columns, + []handler.Condition{ + handler.NewCond(IDPTemplateIDCol, e.ID), + handler.NewCond(IDPTemplateInstanceIDCol, e.Aggregate().InstanceID), + }, + ), + ), nil +} // func (p *idpTemplateProjection) reduceOIDCIDPMigratedAzureAD(event eventstore.Event) (*handler.Statement, error) { // var idpEvent idp.OIDCIDPMigratedAzureADEvent @@ -2174,3 +2214,90 @@ func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer // } // return SAMLCols // } + +func reduceIDPRelationalChangedTemplateColumns(name *string, optionChanges idp.OptionChanges, cols *[]handler.Column) { + if name != nil { + *cols = append(*cols, handler.NewCol(IDPTemplateNameCol, *name)) + } + if optionChanges.IsCreationAllowed != nil { + *cols = append(*cols, handler.NewCol(IDPRelationalAllowCreationCol, *optionChanges.IsCreationAllowed)) + } + if optionChanges.IsLinkingAllowed != nil { + *cols = append(*cols, handler.NewCol(IDPRelationalAllowLinkingCol, *optionChanges.IsLinkingAllowed)) + } + if optionChanges.IsAutoCreation != nil { + *cols = append(*cols, handler.NewCol(IDPRelationalAllowAutoCreationCol, *optionChanges.IsAutoCreation)) + } + if optionChanges.IsAutoUpdate != nil { + *cols = append(*cols, handler.NewCol(IDPRelationalAllowAutoUpdateCol, *optionChanges.IsAutoUpdate)) + } + if optionChanges.AutoLinkingOption != nil { + *cols = append(*cols, handler.NewCol(IDPRelationalAllowAutoLinkingCol, domain.IDPAutoLinkingOption(*optionChanges.AutoLinkingOption).String())) + } +} + +func reduceOAuthIDPRelationalChangedColumns(payload *domain.OAuth, idpEvent *idp.OAuthIDPChangedEvent) bool { + payloadChange := false + if idpEvent.ClientID != nil { + payloadChange = true + payload.ClientID = *idpEvent.ClientID + } + if idpEvent.ClientSecret != nil { + payloadChange = true + payload.ClientSecret = idpEvent.ClientSecret + } + if idpEvent.AuthorizationEndpoint != nil { + payloadChange = true + payload.AuthorizationEndpoint = *idpEvent.AuthorizationEndpoint + } + if idpEvent.TokenEndpoint != nil { + payloadChange = true + payload.TokenEndpoint = *idpEvent.TokenEndpoint + } + if idpEvent.UserEndpoint != nil { + payloadChange = true + payload.UserEndpoint = *idpEvent.UserEndpoint + } + if idpEvent.Scopes != nil { + payloadChange = true + payload.Scopes = idpEvent.Scopes + } + if idpEvent.IDAttribute != nil { + payloadChange = true + payload.IDAttribute = *idpEvent.IDAttribute + } + if idpEvent.UsePKCE != nil { + payloadChange = true + payload.UsePKCE = *idpEvent.UsePKCE + } + return payloadChange +} + +func reduceOIDCIDPRelationalChangedColumns(payload *domain.OIDC, idpEvent *idp.OIDCIDPChangedEvent) bool { + payloadChange := false + if idpEvent.ClientID != nil { + payloadChange = true + payload.ClientID = *idpEvent.ClientID + } + if idpEvent.ClientSecret != nil { + payloadChange = true + payload.ClientSecret = *idpEvent.ClientSecret + } + if idpEvent.Issuer != nil { + payloadChange = true + payload.Issuer = *idpEvent.Issuer + } + if idpEvent.Scopes != nil { + payloadChange = true + payload.Scopes = idpEvent.Scopes + } + if idpEvent.IsIDTokenMapping != nil { + payloadChange = true + payload.IsIDTokenMapping = *idpEvent.IsIDTokenMapping + } + if idpEvent.UsePKCE != nil { + payloadChange = true + payload.UsePKCE = *idpEvent.UsePKCE + } + return payloadChange +} diff --git a/internal/query/projection/projection.go b/internal/query/projection/projection.go index c26f14221a..1f4ca89c6d 100644 --- a/internal/query/projection/projection.go +++ b/internal/query/projection/projection.go @@ -40,6 +40,7 @@ var ( LoginPolicyProjection *handler.Handler IDPProjection *handler.Handler IDPRelationalProjection *handler.Handler + IDPTemplateRelationalProjection *handler.Handler AppProjection *handler.Handler IDPUserLinkProjection *handler.Handler IDPLoginPolicyLinkProjection *handler.Handler @@ -143,6 +144,7 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore, IDPUserLinkProjection = newIDPUserLinkProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_user_links"])) IDPLoginPolicyLinkProjection = newIDPLoginPolicyLinkProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_login_policy_links"])) IDPTemplateProjection = newIDPTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_templates"])) + IDPTemplateRelationalProjection = newIDPTemplateRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_templates-relational"])) MailTemplateProjection = newMailTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["mail_templates"])) MessageTextProjection = newMessageTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["message_texts"])) CustomTextProjection = newCustomTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["custom_texts"])) @@ -320,6 +322,7 @@ func newProjectionsList() { LoginPolicyProjection, IDPProjection, IDPRelationalProjection, + IDPTemplateRelationalProjection, IDPTemplateProjection, AppProjection, IDPUserLinkProjection,