From a6a209c46ac94a5510de62317884bd16cbdcd4cc Mon Sep 17 00:00:00 2001 From: Iraq Jaber Date: Fri, 25 Jul 2025 12:14:28 +0100 Subject: [PATCH] fixup! fixup! added first event --- backend/v3/domain/id_provider.go | 67 +++- backend/v3/domain/idptype_enumer.go | 92 +++-- .../003_identity_providers_table/up.sql | 3 +- .../events_testing/id_provider_test.go | 264 ++++++++++--- .../events_testing/idp_provider_test.go | 63 ---- .../database/repository/id_provider.go | 49 ++- internal/query/projection/idp_relational.go | 356 +++++++----------- 7 files changed, 529 insertions(+), 365 deletions(-) delete mode 100644 backend/v3/storage/database/events_testing/idp_provider_test.go diff --git a/backend/v3/domain/id_provider.go b/backend/v3/domain/id_provider.go index 1924444434..bb7bc11630 100644 --- a/backend/v3/domain/id_provider.go +++ b/backend/v3/domain/id_provider.go @@ -5,20 +5,26 @@ import ( "time" "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/crypto" ) //go:generate enumer -type IDPType -transform lower -trimprefix IDPType type IDPType uint8 const ( - IDPTypeOIDC IDPType = iota - IDPTypeOAUTH - IDPTypeSAML + IDPTypeUnspecified IDPType = iota + IDPTypeOIDC + IDPTypeJWT + IDPTypeOAuth IDPTypeLDAP - IDPTypeGithub + IDPTypeAzureAD + IDPTypeGitHub + IDPTypeGitHubEnterprise + IDPTypeGitLab + IDPTypeGitLabSelfHosted IDPTypeGoogle - IDPTypeMicrosoft IDPTypeApple + IDPTypeSAML ) //go:generate enumer -type IDPState -transform lower -trimprefix IDPState @@ -29,6 +35,16 @@ const ( IDPStateInactive ) +type OIDCMappingField int8 + +const ( + OIDCMappingFieldUnspecified OIDCMappingField = iota + OIDCMappingFieldPreferredLoginName + OIDCMappingFieldEmail + // count is for validation purposes + oidcMappingFieldCount +) + type IdentityProvider struct { InstanceID string `json:"instanceId,omitempty" db:"instance_id"` OrgID *string `json:"orgId,omitempty" db:"org_id"` @@ -46,9 +62,39 @@ type IdentityProvider struct { UpdatedAt time.Time `json:"updatedAt,omitempty" db:"updated_at"` } +type OIDC struct { + IDPConfigID string `json:"idpConfigId"` + ClientID string `json:"clientId,omitempty"` + ClientSecret crypto.CryptoValue `json:"clientSecret,omitempty"` + Issuer string `json:"issuer,omitempty"` + AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"` + TokenEndpoint string `json:"tokenEndpoint,omitempty"` + Scopes []string `json:"scopes,omitempty"` + IDPDisplayNameMapping OIDCMappingField `json:"IDPDisplayNameMapping,omitempty"` + UserNameMapping OIDCMappingField `json:"usernameMapping,omitempty"` +} + +type IDPOIDC struct { + *IdentityProvider + OIDC +} + +type JWT struct { + IDPConfigID string `json:"idpConfigId"` + JWTEndpoint string `json:"jwtEndpoint,omitempty"` + Issuer string `json:"issuer,omitempty"` + KeysEndpoint string `json:"keysEndpoint,omitempty"` + HeaderName string `json:"headerName,omitempty"` +} + +type IDPJWT struct { + *IdentityProvider + JWT +} + // 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 (instnaceID + OrgID + ID) OR (instanceID + OrgID + name) +// as identity_provider can be identified either using (instanceID + OrgID + ID) OR (instanceID + OrgID + name) type IDPIdentifierCondition interface { database.Condition } @@ -101,10 +147,13 @@ type IDProviderRepository interface { idProviderConditions idProviderChanges - Get(ctx context.Context, id IDPIdentifierCondition, instnaceID string, orgID *string) (*IdentityProvider, error) + Get(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IdentityProvider, error) List(ctx context.Context, conditions ...database.Condition) ([]*IdentityProvider, error) Create(ctx context.Context, idp *IdentityProvider) error - Update(ctx context.Context, id IDPIdentifierCondition, instnaceID string, orgID *string, changes ...database.Change) (int64, error) - Delete(ctx context.Context, id IDPIdentifierCondition, instnaceID string, orgID *string) (int64, error) + Update(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string, changes ...database.Change) (int64, error) + Delete(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (int64, error) + + GetOIDC(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPOIDC, error) + GetJWT(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPJWT, error) } diff --git a/backend/v3/domain/idptype_enumer.go b/backend/v3/domain/idptype_enumer.go index 6a7c08e5f3..881fd893f8 100644 --- a/backend/v3/domain/idptype_enumer.go +++ b/backend/v3/domain/idptype_enumer.go @@ -7,11 +7,11 @@ import ( "strings" ) -const _IDPTypeName = "oidcoauthsamlldapgithubgooglemicrosoftapple" +const _IDPTypeName = "unspecifiedoidcjwtoauthldapazureadgithubgithubenterprisegitlabgitlabselfhostedgoogleapplesaml" -var _IDPTypeIndex = [...]uint8{0, 4, 9, 13, 17, 23, 29, 38, 43} +var _IDPTypeIndex = [...]uint8{0, 11, 15, 18, 23, 27, 34, 40, 56, 62, 78, 84, 89, 93} -const _IDPTypeLowerName = "oidcoauthsamlldapgithubgooglemicrosoftapple" +const _IDPTypeLowerName = "unspecifiedoidcjwtoauthldapazureadgithubgithubenterprisegitlabgitlabselfhostedgoogleapplesaml" func (i IDPType) String() string { if i >= IDPType(len(_IDPTypeIndex)-1) { @@ -24,46 +24,66 @@ func (i IDPType) String() string { // Re-run the stringer command to generate them again. func _IDPTypeNoOp() { var x [1]struct{} - _ = x[IDPTypeOIDC-(0)] - _ = x[IDPTypeOAUTH-(1)] - _ = x[IDPTypeSAML-(2)] - _ = x[IDPTypeLDAP-(3)] - _ = x[IDPTypeGithub-(4)] - _ = x[IDPTypeGoogle-(5)] - _ = x[IDPTypeMicrosoft-(6)] - _ = x[IDPTypeApple-(7)] + _ = x[IDPTypeUnspecified-(0)] + _ = x[IDPTypeOIDC-(1)] + _ = x[IDPTypeJWT-(2)] + _ = x[IDPTypeOAuth-(3)] + _ = x[IDPTypeLDAP-(4)] + _ = x[IDPTypeAzureAD-(5)] + _ = x[IDPTypeGitHub-(6)] + _ = x[IDPTypeGitHubEnterprise-(7)] + _ = x[IDPTypeGitLab-(8)] + _ = x[IDPTypeGitLabSelfHosted-(9)] + _ = x[IDPTypeGoogle-(10)] + _ = x[IDPTypeApple-(11)] + _ = x[IDPTypeSAML-(12)] } -var _IDPTypeValues = []IDPType{IDPTypeOIDC, IDPTypeOAUTH, IDPTypeSAML, IDPTypeLDAP, IDPTypeGithub, IDPTypeGoogle, IDPTypeMicrosoft, IDPTypeApple} +var _IDPTypeValues = []IDPType{IDPTypeUnspecified, IDPTypeOIDC, IDPTypeJWT, IDPTypeOAuth, IDPTypeLDAP, IDPTypeAzureAD, IDPTypeGitHub, IDPTypeGitHubEnterprise, IDPTypeGitLab, IDPTypeGitLabSelfHosted, IDPTypeGoogle, IDPTypeApple, IDPTypeSAML} var _IDPTypeNameToValueMap = map[string]IDPType{ - _IDPTypeName[0:4]: IDPTypeOIDC, - _IDPTypeLowerName[0:4]: IDPTypeOIDC, - _IDPTypeName[4:9]: IDPTypeOAUTH, - _IDPTypeLowerName[4:9]: IDPTypeOAUTH, - _IDPTypeName[9:13]: IDPTypeSAML, - _IDPTypeLowerName[9:13]: IDPTypeSAML, - _IDPTypeName[13:17]: IDPTypeLDAP, - _IDPTypeLowerName[13:17]: IDPTypeLDAP, - _IDPTypeName[17:23]: IDPTypeGithub, - _IDPTypeLowerName[17:23]: IDPTypeGithub, - _IDPTypeName[23:29]: IDPTypeGoogle, - _IDPTypeLowerName[23:29]: IDPTypeGoogle, - _IDPTypeName[29:38]: IDPTypeMicrosoft, - _IDPTypeLowerName[29:38]: IDPTypeMicrosoft, - _IDPTypeName[38:43]: IDPTypeApple, - _IDPTypeLowerName[38:43]: IDPTypeApple, + _IDPTypeName[0:11]: IDPTypeUnspecified, + _IDPTypeLowerName[0:11]: IDPTypeUnspecified, + _IDPTypeName[11:15]: IDPTypeOIDC, + _IDPTypeLowerName[11:15]: IDPTypeOIDC, + _IDPTypeName[15:18]: IDPTypeJWT, + _IDPTypeLowerName[15:18]: IDPTypeJWT, + _IDPTypeName[18:23]: IDPTypeOAuth, + _IDPTypeLowerName[18:23]: IDPTypeOAuth, + _IDPTypeName[23:27]: IDPTypeLDAP, + _IDPTypeLowerName[23:27]: IDPTypeLDAP, + _IDPTypeName[27:34]: IDPTypeAzureAD, + _IDPTypeLowerName[27:34]: IDPTypeAzureAD, + _IDPTypeName[34:40]: IDPTypeGitHub, + _IDPTypeLowerName[34:40]: IDPTypeGitHub, + _IDPTypeName[40:56]: IDPTypeGitHubEnterprise, + _IDPTypeLowerName[40:56]: IDPTypeGitHubEnterprise, + _IDPTypeName[56:62]: IDPTypeGitLab, + _IDPTypeLowerName[56:62]: IDPTypeGitLab, + _IDPTypeName[62:78]: IDPTypeGitLabSelfHosted, + _IDPTypeLowerName[62:78]: IDPTypeGitLabSelfHosted, + _IDPTypeName[78:84]: IDPTypeGoogle, + _IDPTypeLowerName[78:84]: IDPTypeGoogle, + _IDPTypeName[84:89]: IDPTypeApple, + _IDPTypeLowerName[84:89]: IDPTypeApple, + _IDPTypeName[89:93]: IDPTypeSAML, + _IDPTypeLowerName[89:93]: IDPTypeSAML, } var _IDPTypeNames = []string{ - _IDPTypeName[0:4], - _IDPTypeName[4:9], - _IDPTypeName[9:13], - _IDPTypeName[13:17], - _IDPTypeName[17:23], - _IDPTypeName[23:29], - _IDPTypeName[29:38], - _IDPTypeName[38:43], + _IDPTypeName[0:11], + _IDPTypeName[11:15], + _IDPTypeName[15:18], + _IDPTypeName[18:23], + _IDPTypeName[23:27], + _IDPTypeName[27:34], + _IDPTypeName[34:40], + _IDPTypeName[40:56], + _IDPTypeName[56:62], + _IDPTypeName[62:78], + _IDPTypeName[78:84], + _IDPTypeName[84:89], + _IDPTypeName[89:93], } // IDPTypeString retrieves an enum value from the enum constants string name. 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 a21ba939de..c91697cf71 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 @@ -5,6 +5,7 @@ CREATE TYPE zitadel.idp_state AS ENUM ( CREATE TYPE zitadel.idp_type AS ENUM ( 'oidc', + 'jwt', 'oauth', 'saml', 'ldap', @@ -20,7 +21,7 @@ CREATE TABLE zitadel.identity_providers ( , id TEXT NOT NULL CHECK (id <> '') , state zitadel.idp_state NOT NULL DEFAULT 'active' , name TEXT NOT NULL CHECK (name <> '') - , type zitadel.idp_type NOT NULL + , type zitadel.idp_type -- NOT NULL , allow_creation BOOLEAN NOT NULL DEFAULT TRUE , allow_auto_creation BOOLEAN NOT NULL DEFAULT TRUE , allow_auto_update BOOLEAN NOT NULL DEFAULT TRUE 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 b1fc23fcd7..a0252d9a72 100644 --- a/backend/v3/storage/database/events_testing/id_provider_test.go +++ b/backend/v3/storage/database/events_testing/id_provider_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/zitadel/zitadel/backend/v3/domain" + "github.com/zitadel/zitadel/backend/v3/storage/database" "github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/pkg/grpc/admin" @@ -25,7 +26,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { name := gofakeit.Name() beforeCreate := time.Now() - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -41,7 +42,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { idpRepo := repository.IDProviderRepository(pool) - retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) assert.EventuallyWithT(t, func(t *assert.CollectT) { idp, err := idpRepo.Get(CTX, idpRepo.NameCondition(name), @@ -51,7 +52,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { require.NoError(t, err) // event iam.idp.config.added - assert.Equal(t, addOCID.IdpId, idp.ID) + assert.Equal(t, addOIDC.IdpId, idp.ID) assert.Equal(t, name, idp.Name) assert.Equal(t, instanceID, idp.InstanceID) assert.Equal(t, domain.IDPStateActive.String(), idp.State) @@ -65,7 +66,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { t.Run("test idp update reduces", func(t *testing.T) { name := gofakeit.Name() - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -82,7 +83,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { beforeCreate := time.Now() _, err = AdminClient.UpdateIDP(CTX, &admin.UpdateIDPRequest{ - IdpId: addOCID.IdpId, + IdpId: addOIDC.IdpId, Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED, AutoRegister: false, @@ -96,14 +97,13 @@ func TestServer_TestIDProviderReduces(t *testing.T) { assert.EventuallyWithT(t, func(t *assert.CollectT) { idp, err := idpRepo.Get(CTX, idpRepo.NameCondition(name), - // idpRepo.IDCondition(addOCID.IdpId), instanceID, nil, ) require.NoError(t, err) - // event "iam.idp.config.changed" - assert.Equal(t, addOCID.IdpId, idp.ID) + // event iam.idp.config.changed + assert.Equal(t, addOIDC.IdpId, idp.ID) assert.Equal(t, name, idp.Name) assert.Equal(t, false, idp.AllowAutoCreation) assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED), idp.StylingType) @@ -114,7 +114,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { t.Run("test idp deactivate reduces", func(t *testing.T) { name := gofakeit.Name() - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -130,7 +130,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { // deactivate idp beforeCreate := time.Now() _, err = AdminClient.DeactivateIDP(CTX, &admin.DeactivateIDPRequest{ - IdpId: addOCID.IdpId, + IdpId: addOIDC.IdpId, }) afterCreate := time.Now() require.NoError(t, err) @@ -140,15 +140,14 @@ func TestServer_TestIDProviderReduces(t *testing.T) { retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) assert.EventuallyWithT(t, func(t *assert.CollectT) { idp, err := idpRepo.Get(CTX, - // idpRepo.NameCondition(name), - idpRepo.IDCondition(addOCID.IdpId), + idpRepo.IDCondition(addOIDC.IdpId), instanceID, nil, ) require.NoError(t, err) - // event "iam.idp.config.deactivated" - assert.Equal(t, addOCID.IdpId, idp.ID) + // event iam.idp.config.deactivated + assert.Equal(t, addOIDC.IdpId, idp.ID) assert.Equal(t, domain.IDPStateInactive.String(), idp.State) assert.WithinRange(t, idp.UpdatedAt, beforeCreate, afterCreate) }, retryDuration, tick) @@ -157,7 +156,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { t.Run("test idp reactivate reduces", func(t *testing.T) { name := gofakeit.Name() - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -174,28 +173,27 @@ func TestServer_TestIDProviderReduces(t *testing.T) { // deactivate idp _, err = AdminClient.DeactivateIDP(CTX, &admin.DeactivateIDPRequest{ - IdpId: addOCID.IdpId, + IdpId: addOIDC.IdpId, }) require.NoError(t, err) // wait for idp to be deactivated retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) assert.EventuallyWithT(t, func(t *assert.CollectT) { idp, err := idpRepo.Get(CTX, - idpRepo.IDCondition(addOCID.IdpId), + idpRepo.IDCondition(addOIDC.IdpId), instanceID, nil, ) require.NoError(t, err) - assert.Equal(t, addOCID.IdpId, idp.ID) + assert.Equal(t, addOIDC.IdpId, idp.ID) assert.Equal(t, domain.IDPStateInactive.String(), idp.State) }, retryDuration, tick) // reactivate idp - // beforeCreate := time.Now().Add(-time.Second) beforeCreate := time.Now() _, err = AdminClient.ReactivateIDP(CTX, &admin.ReactivateIDPRequest{ - IdpId: addOCID.IdpId, + IdpId: addOIDC.IdpId, }) afterCreate := time.Now() require.NoError(t, err) @@ -203,15 +201,14 @@ func TestServer_TestIDProviderReduces(t *testing.T) { retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) assert.EventuallyWithT(t, func(t *assert.CollectT) { idp, err := idpRepo.Get(CTX, - // idpRepo.NameCondition(name), - idpRepo.IDCondition(addOCID.IdpId), + idpRepo.IDCondition(addOIDC.IdpId), instanceID, nil, ) require.NoError(t, err) - // event "iam.idp.config.reactivated" - assert.Equal(t, addOCID.IdpId, idp.ID) + // event iam.idp.config.reactivated + assert.Equal(t, addOIDC.IdpId, idp.ID) assert.Equal(t, domain.IDPStateActive.String(), idp.State) assert.WithinRange(t, idp.UpdatedAt, beforeCreate, afterCreate) }, retryDuration, tick) @@ -221,7 +218,7 @@ func TestServer_TestIDProviderReduces(t *testing.T) { name := gofakeit.Name() // add idp - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -238,31 +235,28 @@ func TestServer_TestIDProviderReduces(t *testing.T) { // remove idp _, err = AdminClient.RemoveIDP(CTX, &admin.RemoveIDPRequest{ - IdpId: addOCID.IdpId, + IdpId: addOIDC.IdpId, }) require.NoError(t, err) - // retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*20) assert.EventuallyWithT(t, func(t *assert.CollectT) { - idp, err := idpRepo.Delete(CTX, - // idpRepo.NameCondition(name), - idpRepo.IDCondition(addOCID.IdpId), + _, err := idpRepo.Get(CTX, + idpRepo.IDCondition(addOIDC.IdpId), instanceID, nil, ) - require.NoError(t, err) - // event "iam.idp.config.remove" - assert.Nil(t, idp) + // event iam.idp.config.remove + require.ErrorIs(t, &database.NoRowFoundError{}, err) }, retryDuration, tick) }) t.Run("test idp oidc addded reduces", func(t *testing.T) { name := gofakeit.Name() - // add idp - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + // add oidc + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -277,8 +271,35 @@ func TestServer_TestIDProviderReduces(t *testing.T) { idpRepo := repository.IDProviderRepository(pool) - // remove idp - _, err = AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + oidc, err := idpRepo.GetOIDC(CTX, + idpRepo.IDCondition(addOIDC.IdpId), + instanceID, + nil, + ) + require.NoError(t, err) + + // event org.idp.oidc.config.added + // idp + assert.Equal(t, addOIDC.IdpId, oidc.ID) + assert.Equal(t, domain.IDPTypeOIDC.String(), oidc.Type) + + // oidc + assert.Equal(t, addOIDC.IdpId, oidc.IDPConfigID) + assert.Equal(t, "issuer", oidc.Issuer) + assert.Equal(t, "clientID", oidc.ClientID) + assert.Equal(t, []string{"scope"}, oidc.Scopes) + assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.IDPDisplayNameMapping) + assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.UserNameMapping) + }, retryDuration, tick) + }) + + t.Run("test idp oidc changed reduces", func(t *testing.T) { + name := gofakeit.Name() + + // add oidc + addOIDC, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ Name: name, StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, ClientId: "clientID", @@ -291,19 +312,174 @@ func TestServer_TestIDProviderReduces(t *testing.T) { }) require.NoError(t, err) - // retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) - retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*20) + idpRepo := repository.IDProviderRepository(pool) + + // check original values for OCID + var oidc *domain.IDPOIDC + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) assert.EventuallyWithT(t, func(t *assert.CollectT) { - idp, err := idpRepo.Delete(CTX, - // idpRepo.NameCondition(name), - idpRepo.IDCondition(addOCID.IdpId), + oidc, err = idpRepo.GetOIDC(CTX, idpRepo.IDCondition(addOIDC.IdpId), instanceID, nil) + require.NoError(t, err) + }, retryDuration, tick) + + // idp + assert.Equal(t, addOIDC.IdpId, oidc.ID) + assert.Equal(t, domain.IDPTypeOIDC.String(), oidc.Type) + + // oidc + assert.Equal(t, addOIDC.IdpId, oidc.IDPConfigID) + assert.Equal(t, "issuer", oidc.Issuer) + assert.Equal(t, "clientID", oidc.ClientID) + assert.Equal(t, []string{"scope"}, oidc.Scopes) + assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.IDPDisplayNameMapping) + assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.UserNameMapping) + + beforeCreate := time.Now() + _, err = AdminClient.UpdateIDPOIDCConfig(CTX, &admin.UpdateIDPOIDCConfigRequest{ + IdpId: addOIDC.IdpId, + ClientId: "new_clientID", + ClientSecret: "new_clientSecret", + Issuer: "new_issuer", + Scopes: []string{"new_scope"}, + DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME, + UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME, + }) + 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.IdpId), instanceID, nil, ) require.NoError(t, err) - // event "iam.idp.config.remove" - assert.Nil(t, idp) + // event org.idp.oidc.config.changed + // idp + assert.Equal(t, addOIDC.IdpId, updateOIDC.ID) + assert.Equal(t, domain.IDPTypeOIDC.String(), updateOIDC.Type) + assert.WithinRange(t, updateOIDC.UpdatedAt, beforeCreate, afterCreate) + + // oidc + assert.Equal(t, addOIDC.IdpId, updateOIDC.IDPConfigID) + assert.Equal(t, "new_issuer", updateOIDC.Issuer) + assert.Equal(t, "new_clientID", updateOIDC.ClientID) + assert.NotEqual(t, oidc.ClientSecret, updateOIDC.ClientSecret) + assert.Equal(t, []string{"new_scope"}, updateOIDC.Scopes) + assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME), updateOIDC.IDPDisplayNameMapping) + assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME), updateOIDC.UserNameMapping) + }, retryDuration, tick) + }) + + t.Run("test idp jwt addded reduces", func(t *testing.T) { + name := gofakeit.Name() + + // add jwt + addJWT, err := AdminClient.AddJWTIDP(CTX, &admin.AddJWTIDPRequest{ + Name: name, + StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, + JwtEndpoint: "jwtEndpoint", + Issuer: "issuer", + KeysEndpoint: "keyEndpoint", + HeaderName: "headerName", + AutoRegister: true, + }) + require.NoError(t, err) + + idpRepo := repository.IDProviderRepository(pool) + + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + jwt, err := idpRepo.GetJWT(CTX, + idpRepo.IDCondition(addJWT.IdpId), + instanceID, + nil, + ) + require.NoError(t, err) + + // event org.idp.jwt.config.added + // idp + assert.Equal(t, addJWT.IdpId, jwt.ID) + assert.Equal(t, domain.IDPTypeJWT.String(), jwt.Type) + + // jwt + assert.Equal(t, addJWT.IdpId, jwt.IDPConfigID) + assert.Equal(t, "jwtEndpoint", jwt.JWTEndpoint) + assert.Equal(t, "issuer", jwt.Issuer) + assert.Equal(t, "keyEndpoint", jwt.KeysEndpoint) + assert.Equal(t, "headerName", jwt.HeaderName) + }, retryDuration, tick) + }) + + t.Run("test idp jwt changed reduces", func(t *testing.T) { + name := gofakeit.Name() + + // add jwt + addJWT, err := AdminClient.AddJWTIDP(CTX, &admin.AddJWTIDPRequest{ + Name: name, + StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, + JwtEndpoint: "jwtEndpoint", + Issuer: "issuer", + KeysEndpoint: "keyEndpoint", + HeaderName: "headerName", + AutoRegister: true, + }) + require.NoError(t, err) + + idpRepo := repository.IDProviderRepository(pool) + + // check original values for jwt + var jwt *domain.IDPJWT + retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + jwt, err = idpRepo.GetJWT(CTX, idpRepo.IDCondition(addJWT.IdpId), instanceID, nil) + require.NoError(t, err) + }, retryDuration, tick) + + // idp + assert.Equal(t, addJWT.IdpId, jwt.ID) + assert.Equal(t, domain.IDPTypeJWT.String(), jwt.Type) + + // jwt + assert.Equal(t, addJWT.IdpId, jwt.IDPConfigID) + assert.Equal(t, "jwtEndpoint", jwt.JWTEndpoint) + assert.Equal(t, "issuer", jwt.Issuer) + assert.Equal(t, "keyEndpoint", jwt.KeysEndpoint) + assert.Equal(t, "headerName", jwt.HeaderName) + + beforeCreate := time.Now() + _, err = AdminClient.UpdateIDPJWTConfig(CTX, &admin.UpdateIDPJWTConfigRequest{ + IdpId: addJWT.IdpId, + JwtEndpoint: "new_jwtEndpoint", + Issuer: "new_issuer", + KeysEndpoint: "new_keyEndpoint", + HeaderName: "new_headerName", + }) + afterCreate := time.Now() + require.NoError(t, err) + + retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5) + assert.EventuallyWithT(t, func(t *assert.CollectT) { + updateJWT, err := idpRepo.GetJWT(CTX, + idpRepo.IDCondition(addJWT.IdpId), + instanceID, + nil, + ) + require.NoError(t, err) + + // event org.idp.jwt.config.changed + // idp + assert.Equal(t, addJWT.IdpId, updateJWT.ID) + assert.Equal(t, domain.IDPTypeJWT.String(), updateJWT.Type) + assert.WithinRange(t, updateJWT.UpdatedAt, beforeCreate, afterCreate) + + // jwt + assert.Equal(t, addJWT.IdpId, updateJWT.IDPConfigID) + assert.Equal(t, "new_jwtEndpoint", updateJWT.JWTEndpoint) + assert.Equal(t, "new_issuer", updateJWT.Issuer) + assert.Equal(t, "new_keyEndpoint", updateJWT.KeysEndpoint) }, retryDuration, tick) }) } diff --git a/backend/v3/storage/database/events_testing/idp_provider_test.go b/backend/v3/storage/database/events_testing/idp_provider_test.go deleted file mode 100644 index ea3f0cef86..0000000000 --- a/backend/v3/storage/database/events_testing/idp_provider_test.go +++ /dev/null @@ -1,63 +0,0 @@ -//go:build integration - -package events_test - -import ( - "testing" - "time" - - "github.com/brianvoe/gofakeit/v6" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/zitadel/zitadel/backend/v3/domain" - "github.com/zitadel/zitadel/backend/v3/storage/database/repository" - "github.com/zitadel/zitadel/internal/integration" - "github.com/zitadel/zitadel/pkg/grpc/admin" - "github.com/zitadel/zitadel/pkg/grpc/idp" - idp_grpc "github.com/zitadel/zitadel/pkg/grpc/idp" -) - -func TestServer_TestIDProviderReduces(t *testing.T) { - instanceID := Instance.ID() - - t.Run("test idp add reduces", func(t *testing.T) { - name := gofakeit.Name() - - beforeCreate := time.Now() - addOCID, err := AdminClient.AddOIDCIDP(CTX, &admin.AddOIDCIDPRequest{ - Name: name, - StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE, - ClientId: "clientID", - ClientSecret: "clientSecret", - Issuer: "issuer", - Scopes: []string{"scope"}, - DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL, - UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL, - AutoRegister: true, - }) - require.NoError(t, err) - afterCreate := time.Now() - - idpRepo := repository.IDProviderRepository(pool) - - retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Minute) - assert.EventuallyWithT(t, func(t *assert.CollectT) { - idp, err := idpRepo.Get(CTX, - idpRepo.NameCondition(name), - instanceID, - nil, - ) - require.NoError(t, err) - - // event iam.idp.config.added - assert.Equal(t, addOCID.IdpId, idp.ID) - assert.Equal(t, name, idp.Name) - assert.Equal(t, instanceID, idp.InstanceID) - assert.Equal(t, domain.OrgStateActive.String(), idp.State) - assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), idp.StylingType) - assert.WithinRange(t, idp.CreatedAt, beforeCreate, afterCreate) - assert.WithinRange(t, idp.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 ad95e75aa4..504c6fd744 100644 --- a/backend/v3/storage/database/repository/id_provider.go +++ b/backend/v3/storage/database/repository/id_provider.go @@ -2,6 +2,7 @@ package repository import ( "context" + "encoding/json" "errors" "github.com/zitadel/zitadel/backend/v3/domain" @@ -26,12 +27,12 @@ const queryIDProviderStmt = `SELECT instance_id, org_id, id, state, name, type, ` allow_auto_update, allow_linking, styling_type, payload, created_at, updated_at` + ` FROM zitadel.identity_providers` -func (i *idProvider) Get(ctx context.Context, id domain.IDPIdentifierCondition, instnaceID string, orgID *string) (*domain.IdentityProvider, error) { +func (i *idProvider) Get(ctx context.Context, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IdentityProvider, error) { builder := database.StatementBuilder{} builder.WriteString(queryIDProviderStmt) - conditions := []database.Condition{id, i.InstanceIDCondition(instnaceID), i.OrgIDCondition(orgID)} + conditions := []database.Condition{id, i.InstanceIDCondition(instanceID), i.OrgIDCondition(orgID)} writeCondition(&builder, database.And(conditions...)) @@ -118,6 +119,50 @@ func (i *idProvider) Delete(ctx context.Context, id domain.IDPIdentifierConditio return i.client.Exec(ctx, builder.String(), builder.Args()...) } +func (i *idProvider) GetOIDC(ctx context.Context, id domain.IDPIdentifierCondition, instnaceID string, orgID *string) (*domain.IDPOIDC, error) { + idpOIDC := &domain.IDPOIDC{} + var err error + + idpOIDC.IdentityProvider, err = i.Get(ctx, id, instnaceID, orgID) + if err != nil { + return nil, err + } + + if idpOIDC.Type != domain.IDPTypeOIDC.String() { + // TODO + return nil, nil + } + + err = json.Unmarshal([]byte(*idpOIDC.Payload), idpOIDC) + if err != nil { + return nil, err + } + + return idpOIDC, nil +} + +func (i *idProvider) GetJWT(ctx context.Context, id domain.IDPIdentifierCondition, instnaceID string, orgID *string) (*domain.IDPJWT, error) { + idpJWT := &domain.IDPJWT{} + var err error + + idpJWT.IdentityProvider, err = i.Get(ctx, id, instnaceID, orgID) + if err != nil { + return nil, err + } + + if idpJWT.Type != domain.IDPTypeJWT.String() { + // TODO + return nil, nil + } + + err = json.Unmarshal([]byte(*idpJWT.Payload), idpJWT) + if err != nil { + return nil, err + } + + return idpJWT, nil +} + // ------------------------------------------------------------- // columns // ------------------------------------------------------------- diff --git a/internal/query/projection/idp_relational.go b/internal/query/projection/idp_relational.go index fa35294dcc..db7dec1cf1 100644 --- a/internal/query/projection/idp_relational.go +++ b/internal/query/projection/idp_relational.go @@ -2,12 +2,13 @@ package projection import ( "context" + "encoding/json" "github.com/zitadel/zitadel/backend/v3/domain" - "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres" + "github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler/v2" - "github.com/zitadel/zitadel/internal/repository/idpconfig" "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/zerrors" @@ -17,12 +18,20 @@ const ( IDPRelationalTable = "zitadel.identity_providers" IDPRelationalOrgIdCol = "org_id" IDPRelationalAllowAutoCreationCol = "allow_auto_creation" + IDPRelationalPayloadCol = "payload" ) -type idpRelationalProjection struct{} +type idpRelationalProjection struct { + idpRepo domain.IDProviderRepository +} func newIDPRelationalProjection(ctx context.Context, config handler.Config) *handler.Handler { - return handler.NewHandler(ctx, &config, new(idpRelationalProjection)) + client := postgres.PGxPool(config.Client.Pool) + idpRepo := repository.IDProviderRepository(client) + + return handler.NewHandler(ctx, &config, &idpRelationalProjection{ + idpRepo: idpRepo, + }) } func (*idpRelationalProjection) Name() string { @@ -58,18 +67,18 @@ func (p *idpRelationalProjection) Reducers() []handler.AggregateReducer { Event: instance.IDPOIDCConfigAddedEventType, Reduce: p.reduceOIDCRelationalConfigAdded, }, - // { - // Event: instance.IDPOIDCConfigChangedEventType, - // Reduce: p.reduceOIDCConfigChanged, - // }, - // { - // Event: instance.IDPJWTConfigAddedEventType, - // Reduce: p.reduceJWTConfigAdded, - // }, - // { - // Event: instance.IDPJWTConfigChangedEventType, - // Reduce: p.reduceJWTConfigChanged, - // }, + { + Event: instance.IDPOIDCConfigChangedEventType, + Reduce: p.reduceOIDCRelationalConfigChanged, + }, + { + Event: instance.IDPJWTConfigAddedEventType, + Reduce: p.reduceJWTRelationalConfigAdded, + }, + { + Event: instance.IDPJWTConfigChangedEventType, + Reduce: p.reduceJWTConfigChanged, + }, // { // Event: instance.InstanceRemovedEventType, // Reduce: reduceInstanceRemovedHelper(IDPInstanceIDCol), @@ -95,8 +104,7 @@ func (p *idpRelationalProjection) reduceIDPRelationalAdded(event eventstore.Even handler.NewCol(IDPNameCol, e.Name), handler.NewCol(IDPStylingTypeCol, e.StylingType), handler.NewCol(IDPRelationalAllowAutoCreationCol, e.AutoRegister), - handler.NewCol(IDPTypeCol, domain.IDPTypeOIDC.String()), - handler.NewCol(UpdatedAt, e.CreationDate()), + // handler.NewCol(IDPTypeCol, domain.IDPTypeOIDC.String()), handler.NewCol(CreatedAt, e.CreationDate()), }, ), nil @@ -122,10 +130,6 @@ func (p *idpRelationalProjection) reduceIDPRelationalChanged(event eventstore.Ev return handler.NewNoOpStatement(e), nil } - cols = append(cols, - handler.NewCol(UpdatedAt, e.CreationDate()), - ) - return handler.NewUpdateStatement( e, cols, @@ -137,16 +141,6 @@ func (p *idpRelationalProjection) reduceIDPRelationalChanged(event eventstore.Ev } func (p *idpRelationalProjection) reduceIDRelationalPDeactivated(event eventstore.Event) (*handler.Statement, error) { - // var idpEvent idpconfig.IDPConfigDeactivatedEvent - // switch e := event.(type) { - // case *org.IDPConfigDeactivatedEvent: - // idpEvent = e.IDPConfigDeactivatedEvent - // case *instance.IDPConfigDeactivatedEvent: - // idpEvent = e.IDPConfigDeactivatedEvent - // default: - // return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-94O5l", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigDeactivatedEventType, instance.IDPConfigDeactivatedEventType}) - // } - e, ok := event.(*instance.IDPConfigDeactivatedEvent) if !ok { return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-94O5l", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigDeactivatedEventType, instance.IDPConfigDeactivatedEventType}) @@ -156,7 +150,6 @@ func (p *idpRelationalProjection) reduceIDRelationalPDeactivated(event eventstor e, []handler.Column{ handler.NewCol(IDPStateCol, domain.IDPStateInactive.String()), - handler.NewCol(UpdatedAt, e.CreationDate()), }, []handler.Condition{ handler.NewCond(IDPIDCol, e.ConfigID), @@ -175,7 +168,6 @@ func (p *idpRelationalProjection) reduceIDPRelationalReactivated(event eventstor e, []handler.Column{ handler.NewCol(IDPStateCol, domain.IDPStateActive.String()), - handler.NewCol(UpdatedAt, e.CreationDate()), }, []handler.Condition{ handler.NewCond(IDPIDCol, e.ConfigID), @@ -200,199 +192,143 @@ func (p *idpRelationalProjection) reduceIDPRelationalRemoved(event eventstore.Ev } func (p *idpRelationalProjection) reduceOIDCRelationalConfigAdded(event eventstore.Event) (*handler.Statement, error) { - var idpEvent idpconfig.OIDCConfigAddedEvent - switch e := event.(type) { - case *org.IDPOIDCConfigAddedEvent: - idpEvent = e.OIDCConfigAddedEvent - case *instance.IDPOIDCConfigAddedEvent: - idpEvent = e.OIDCConfigAddedEvent - default: + e, ok := event.(*instance.IDPOIDCConfigAddedEvent) + if !ok { return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-2FuAA", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPOIDCConfigAddedEventType, instance.IDPOIDCConfigAddedEventType}) } - return handler.NewMultiStatement(&idpEvent, - handler.AddUpdateStatement( - []handler.Column{ - handler.NewCol(IDPChangeDateCol, idpEvent.CreationDate()), - handler.NewCol(IDPSequenceCol, idpEvent.Sequence()), - handler.NewCol(IDPTypeCol, domain.IDPConfigTypeOIDC), - }, - []handler.Condition{ - handler.NewCond(IDPIDCol, idpEvent.IDPConfigID), - handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID), - }, - ), - handler.AddCreateStatement( - []handler.Column{ - handler.NewCol(OIDCConfigIDPIDCol, idpEvent.IDPConfigID), - handler.NewCol(OIDCConfigInstanceIDCol, idpEvent.Aggregate().InstanceID), - handler.NewCol(OIDCConfigClientIDCol, idpEvent.ClientID), - handler.NewCol(OIDCConfigClientSecretCol, idpEvent.ClientSecret), - handler.NewCol(OIDCConfigIssuerCol, idpEvent.Issuer), - handler.NewCol(OIDCConfigScopesCol, database.TextArray[string](idpEvent.Scopes)), - handler.NewCol(OIDCConfigDisplayNameMappingCol, idpEvent.IDPDisplayNameMapping), - handler.NewCol(OIDCConfigUsernameMappingCol, idpEvent.UserNameMapping), - handler.NewCol(OIDCConfigAuthorizationEndpointCol, idpEvent.AuthorizationEndpoint), - handler.NewCol(OIDCConfigTokenEndpointCol, idpEvent.TokenEndpoint), - }, - handler.WithTableSuffix(IDPOIDCSuffix), - ), + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } + + return handler.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPRelationalPayloadCol, payload), + handler.NewCol(IDPTypeCol, domain.IDPTypeOIDC.String()), + }, + []handler.Condition{ + handler.NewCond(IDPIDCol, e.IDPConfigID), + }, ), nil } -// func (p *idpRelationalProjection) reduceOIDCConfigChanged(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idpconfig.OIDCConfigChangedEvent -// switch e := event.(type) { -// case *org.IDPOIDCConfigChangedEvent: -// idpEvent = e.OIDCConfigChangedEvent -// case *instance.IDPOIDCConfigChangedEvent: -// idpEvent = e.OIDCConfigChangedEvent -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-x2IVI", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPOIDCConfigChangedEventType, instance.IDPOIDCConfigChangedEventType}) -// } +func (p *idpRelationalProjection) reduceOIDCRelationalConfigChanged(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.IDPOIDCConfigChangedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-x2IBI", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPOIDCConfigChangedEventType, instance.IDPOIDCConfigChangedEventType}) + } -// cols := make([]handler.Column, 0, 8) + oidc, err := p.idpRepo.GetOIDC(context.Background(), p.idpRepo.IDCondition(e.IDPConfigID), e.Agg.InstanceID, nil) + if err != nil { + return nil, err + } -// if idpEvent.ClientID != nil { -// cols = append(cols, handler.NewCol(OIDCConfigClientIDCol, *idpEvent.ClientID)) -// } -// if idpEvent.ClientSecret != nil { -// cols = append(cols, handler.NewCol(OIDCConfigClientSecretCol, idpEvent.ClientSecret)) -// } -// if idpEvent.Issuer != nil { -// cols = append(cols, handler.NewCol(OIDCConfigIssuerCol, *idpEvent.Issuer)) -// } -// if idpEvent.AuthorizationEndpoint != nil { -// cols = append(cols, handler.NewCol(OIDCConfigAuthorizationEndpointCol, *idpEvent.AuthorizationEndpoint)) -// } -// if idpEvent.TokenEndpoint != nil { -// cols = append(cols, handler.NewCol(OIDCConfigTokenEndpointCol, *idpEvent.TokenEndpoint)) -// } -// if idpEvent.Scopes != nil { -// cols = append(cols, handler.NewCol(OIDCConfigScopesCol, database.TextArray[string](idpEvent.Scopes))) -// } -// if idpEvent.IDPDisplayNameMapping != nil { -// cols = append(cols, handler.NewCol(OIDCConfigDisplayNameMappingCol, *idpEvent.IDPDisplayNameMapping)) -// } -// if idpEvent.UserNameMapping != nil { -// cols = append(cols, handler.NewCol(OIDCConfigUsernameMappingCol, *idpEvent.UserNameMapping)) -// } + if e.ClientID != nil { + oidc.ClientID = *e.ClientID + } + if e.ClientSecret != nil { + oidc.ClientSecret = *e.ClientSecret + } + if e.Issuer != nil { + oidc.Issuer = *e.Issuer + } + if e.AuthorizationEndpoint != nil { + oidc.AuthorizationEndpoint = *e.AuthorizationEndpoint + } + if e.TokenEndpoint != nil { + oidc.TokenEndpoint = *e.TokenEndpoint + } + if e.Scopes != nil { + oidc.Scopes = e.Scopes + } + if e.IDPDisplayNameMapping != nil { + oidc.IDPDisplayNameMapping = domain.OIDCMappingField(*e.IDPDisplayNameMapping) + } + if e.UserNameMapping != nil { + oidc.UserNameMapping = domain.OIDCMappingField(*e.UserNameMapping) + } -// if len(cols) == 0 { -// return handler.NewNoOpStatement(&idpEvent), nil -// } + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } -// return handler.NewMultiStatement(&idpEvent, -// handler.AddUpdateStatement( -// []handler.Column{ -// handler.NewCol(IDPChangeDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPSequenceCol, idpEvent.Sequence()), -// }, -// []handler.Condition{ -// handler.NewCond(IDPIDCol, idpEvent.IDPConfigID), -// handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// ), -// handler.AddUpdateStatement( -// cols, -// []handler.Condition{ -// handler.NewCond(OIDCConfigIDPIDCol, idpEvent.IDPConfigID), -// handler.NewCond(OIDCConfigInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// handler.WithTableSuffix(IDPOIDCSuffix), -// ), -// ), nil -// } + return handler.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPRelationalPayloadCol, payload), + handler.NewCol(IDPTypeCol, domain.IDPTypeOIDC.String()), + }, + []handler.Condition{ + handler.NewCond(IDPIDCol, e.IDPConfigID), + }, + ), nil +} -// func (p *idpRelationalProjection) reduceJWTConfigAdded(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idpconfig.JWTConfigAddedEvent -// switch e := event.(type) { -// case *org.IDPJWTConfigAddedEvent: -// idpEvent = e.JWTConfigAddedEvent -// case *instance.IDPJWTConfigAddedEvent: -// idpEvent = e.JWTConfigAddedEvent -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-qvPdb", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPJWTConfigAddedEventType, instance.IDPJWTConfigAddedEventType}) -// } +func (p *idpRelationalProjection) reduceJWTRelationalConfigAdded(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.IDPJWTConfigAddedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-qvPdb", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPJWTConfigAddedEventType, instance.IDPJWTConfigAddedEventType}) + } + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } -// return handler.NewMultiStatement(&idpEvent, -// handler.AddUpdateStatement( -// []handler.Column{ -// handler.NewCol(IDPChangeDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPSequenceCol, idpEvent.Sequence()), -// handler.NewCol(IDPTypeCol, domain.IDPConfigTypeJWT), -// }, -// []handler.Condition{ -// handler.NewCond(IDPIDCol, idpEvent.IDPConfigID), -// handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// ), + return handler.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPRelationalPayloadCol, payload), + handler.NewCol(IDPTypeCol, domain.IDPTypeJWT.String()), + }, + []handler.Condition{ + handler.NewCond(IDPIDCol, e.IDPConfigID), + }, + ), nil +} -// handler.AddCreateStatement( -// []handler.Column{ -// handler.NewCol(JWTConfigIDPIDCol, idpEvent.IDPConfigID), -// handler.NewCol(JWTConfigInstanceIDCol, idpEvent.Aggregate().InstanceID), -// handler.NewCol(JWTConfigEndpointCol, idpEvent.JWTEndpoint), -// handler.NewCol(JWTConfigIssuerCol, idpEvent.Issuer), -// handler.NewCol(JWTConfigKeysEndpointCol, idpEvent.KeysEndpoint), -// handler.NewCol(JWTConfigHeaderNameCol, idpEvent.HeaderName), -// }, -// handler.WithTableSuffix(IDPJWTSuffix), -// ), -// ), nil -// } +func (p *idpRelationalProjection) reduceJWTConfigChanged(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.IDPJWTConfigChangedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-P2I9I", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPJWTConfigChangedEventType, instance.IDPJWTConfigChangedEventType}) + } -// func (p *idpRelationalProjection) reduceJWTConfigChanged(event eventstore.Event) (*handler.Statement, error) { -// var idpEvent idpconfig.JWTConfigChangedEvent -// switch e := event.(type) { -// case *org.IDPJWTConfigChangedEvent: -// idpEvent = e.JWTConfigChangedEvent -// case *instance.IDPJWTConfigChangedEvent: -// idpEvent = e.JWTConfigChangedEvent -// default: -// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-x2IVI", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPJWTConfigChangedEventType, instance.IDPJWTConfigChangedEventType}) -// } + jwt, err := p.idpRepo.GetJWT(context.Background(), p.idpRepo.IDCondition(e.IDPConfigID), e.Agg.InstanceID, nil) + if err != nil { + return nil, err + } -// cols := make([]handler.Column, 0, 4) + if e.JWTEndpoint != nil { + jwt.JWTEndpoint = *e.JWTEndpoint + } + if e.Issuer != nil { + jwt.Issuer = *e.Issuer + } + if e.KeysEndpoint != nil { + jwt.KeysEndpoint = *e.KeysEndpoint + } + if e.HeaderName != nil { + jwt.HeaderName = *e.HeaderName + } -// if idpEvent.JWTEndpoint != nil { -// cols = append(cols, handler.NewCol(JWTConfigEndpointCol, *idpEvent.JWTEndpoint)) -// } -// if idpEvent.Issuer != nil { -// cols = append(cols, handler.NewCol(JWTConfigIssuerCol, *idpEvent.Issuer)) -// } -// if idpEvent.KeysEndpoint != nil { -// cols = append(cols, handler.NewCol(JWTConfigKeysEndpointCol, *idpEvent.KeysEndpoint)) -// } -// if idpEvent.HeaderName != nil { -// cols = append(cols, handler.NewCol(JWTConfigHeaderNameCol, *idpEvent.HeaderName)) -// } + payload, err := json.Marshal(e) + if err != nil { + return nil, err + } -// if len(cols) == 0 { -// return handler.NewNoOpStatement(&idpEvent), nil -// } - -// return handler.NewMultiStatement(&idpEvent, -// handler.AddUpdateStatement( -// []handler.Column{ -// handler.NewCol(IDPChangeDateCol, idpEvent.CreationDate()), -// handler.NewCol(IDPSequenceCol, idpEvent.Sequence()), -// }, -// []handler.Condition{ -// handler.NewCond(IDPIDCol, idpEvent.IDPConfigID), -// handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// ), -// handler.AddUpdateStatement( -// cols, -// []handler.Condition{ -// handler.NewCond(JWTConfigIDPIDCol, idpEvent.IDPConfigID), -// handler.NewCond(JWTConfigInstanceIDCol, idpEvent.Aggregate().InstanceID), -// }, -// handler.WithTableSuffix(IDPJWTSuffix), -// ), -// ), nil -// } + return handler.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPRelationalPayloadCol, payload), + handler.NewCol(IDPTypeCol, domain.IDPTypeJWT.String()), + }, + []handler.Condition{ + handler.NewCond(IDPIDCol, e.IDPConfigID), + }, + ), nil +} // func (p *idpProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { // e, ok := event.(*org.OrgRemovedEvent)