diff --git a/internal/api/grpc/idp/converter.go b/internal/api/grpc/idp/converter.go index a831555b65..4ff09dec94 100644 --- a/internal/api/grpc/idp/converter.go +++ b/internal/api/grpc/idp/converter.go @@ -487,9 +487,10 @@ func oauthConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.OAut func oidcConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.OIDCIDPTemplate) { providerConfig.Config = &idp_pb.ProviderConfig_Oidc{ Oidc: &idp_pb.GenericOIDCConfig{ - ClientId: template.ClientID, - Issuer: template.Issuer, - Scopes: template.Scopes, + ClientId: template.ClientID, + Issuer: template.Issuer, + Scopes: template.Scopes, + IsIdTokenMapping: template.IsIDTokenMapping, }, } } diff --git a/internal/api/ui/login/external_provider_handler.go b/internal/api/ui/login/external_provider_handler.go index 7e5edab1dd..3886c0f0ad 100644 --- a/internal/api/ui/login/external_provider_handler.go +++ b/internal/api/ui/login/external_provider_handler.go @@ -627,6 +627,11 @@ func (l *Login) oidcProvider(ctx context.Context, identityProvider *query.IDPTem if err != nil { return nil, err } + opts := make([]openid.ProviderOpts, 1, 2) + opts[0] = openid.WithSelectAccount() + if identityProvider.OIDCIDPTemplate.IsIDTokenMapping { + opts = append(opts, openid.WithIDTokenMapping()) + } return openid.New(identityProvider.Name, identityProvider.OIDCIDPTemplate.Issuer, identityProvider.OIDCIDPTemplate.ClientID, @@ -634,7 +639,7 @@ func (l *Login) oidcProvider(ctx context.Context, identityProvider *query.IDPTem l.baseURL(ctx)+EndpointExternalLoginCallback, identityProvider.OIDCIDPTemplate.Scopes, openid.DefaultMapper, - openid.WithSelectAccount(), + opts..., ) } diff --git a/internal/command/idp.go b/internal/command/idp.go index 6e4030b646..7ae7cfd68a 100644 --- a/internal/command/idp.go +++ b/internal/command/idp.go @@ -21,12 +21,13 @@ type GenericOAuthProvider struct { } type GenericOIDCProvider struct { - Name string - Issuer string - ClientID string - ClientSecret string - Scopes []string - IDPOptions idp.Options + Name string + Issuer string + ClientID string + ClientSecret string + Scopes []string + IsIDTokenMapping bool + IDPOptions idp.Options } type JWTProvider struct { diff --git a/internal/command/idp_model.go b/internal/command/idp_model.go index 498955ddd5..452de29198 100644 --- a/internal/command/idp_model.go +++ b/internal/command/idp_model.go @@ -135,12 +135,13 @@ func (wm *OAuthIDPWriteModel) NewChanges( type OIDCIDPWriteModel struct { eventstore.WriteModel - Name string - ID string - Issuer string - ClientID string - ClientSecret *crypto.CryptoValue - Scopes []string + Name string + ID string + Issuer string + ClientID string + ClientSecret *crypto.CryptoValue + Scopes []string + IsIDTokenMapping bool idp.Options State domain.IDPState @@ -174,6 +175,7 @@ func (wm *OIDCIDPWriteModel) reduceAddedEvent(e *idp.OIDCIDPAddedEvent) { wm.ClientID = e.ClientID wm.ClientSecret = e.ClientSecret wm.Scopes = e.Scopes + wm.IsIDTokenMapping = e.IsIDTokenMapping wm.Options = e.Options wm.State = domain.IDPStateActive } @@ -194,6 +196,9 @@ func (wm *OIDCIDPWriteModel) reduceChangedEvent(e *idp.OIDCIDPChangedEvent) { if e.Scopes != nil { wm.Scopes = e.Scopes } + if e.IsIDTokenMapping != nil { + wm.IsIDTokenMapping = *e.IsIDTokenMapping + } wm.Options.ReduceChanges(e.OptionChanges) } @@ -204,6 +209,7 @@ func (wm *OIDCIDPWriteModel) NewChanges( clientSecretString string, secretCrypto crypto.Crypto, scopes []string, + idTokenMapping bool, options idp.Options, ) ([]idp.OIDCIDPChanges, error) { changes := make([]idp.OIDCIDPChanges, 0) @@ -228,6 +234,9 @@ func (wm *OIDCIDPWriteModel) NewChanges( if !reflect.DeepEqual(wm.Scopes, scopes) { changes = append(changes, idp.ChangeOIDCScopes(scopes)) } + if wm.IsIDTokenMapping != idTokenMapping { + changes = append(changes, idp.ChangeOIDCIsIDTokenMapping(idTokenMapping)) + } opts := wm.Options.Changes(options) if !opts.IsZero() { changes = append(changes, idp.ChangeOIDCOptions(opts)) diff --git a/internal/command/instance_idp.go b/internal/command/instance_idp.go index 75e1e5c328..e96f172bee 100644 --- a/internal/command/instance_idp.go +++ b/internal/command/instance_idp.go @@ -614,6 +614,7 @@ func (c *Commands) prepareAddInstanceOIDCProvider(a *instance.Aggregate, writeMo provider.ClientID, secret, provider.Scopes, + provider.IsIDTokenMapping, provider.IDPOptions, ), }, nil @@ -657,6 +658,7 @@ func (c *Commands) prepareUpdateInstanceOIDCProvider(a *instance.Aggregate, writ provider.ClientSecret, c.idpConfigEncryption, provider.Scopes, + provider.IsIDTokenMapping, provider.IDPOptions, ) if err != nil || event == nil { diff --git a/internal/command/instance_idp_model.go b/internal/command/instance_idp_model.go index f11f9e8e28..f2363e54f1 100644 --- a/internal/command/instance_idp_model.go +++ b/internal/command/instance_idp_model.go @@ -166,6 +166,7 @@ func (wm *InstanceOIDCIDPWriteModel) NewChangedEvent( clientSecretString string, secretCrypto crypto.Crypto, scopes []string, + idTokenMapping bool, options idp.Options, ) (*instance.OIDCIDPChangedEvent, error) { @@ -176,6 +177,7 @@ func (wm *InstanceOIDCIDPWriteModel) NewChangedEvent( clientSecretString, secretCrypto, scopes, + idTokenMapping, options, ) if err != nil || len(changes) == 0 { diff --git a/internal/command/instance_idp_test.go b/internal/command/instance_idp_test.go index a79fd8fadc..e4adfee60e 100644 --- a/internal/command/instance_idp_test.go +++ b/internal/command/instance_idp_test.go @@ -7,6 +7,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + openid "github.com/zitadel/oidc/v2/pkg/oidc" "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/crypto" @@ -637,6 +638,470 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { } } +func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + secretCrypto crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + provider GenericOIDCProvider + } + type res struct { + id string + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid name", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{}, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Sgtj5", "")) + }, + }, + }, + { + "invalid issuer", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{ + Name: "name", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Hz6zj", "")) + }, + }, + }, + { + "invalid clientID", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-fb5jm", "")) + }, + }, + }, + { + "invalid clientSecret", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Sfdf4", "")) + }, + }, + }, + { + name: "ok", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID( + "instance1", + instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + nil, + false, + idp.Options{}, + )), + }, + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + ClientSecret: "clientSecret", + }, + }, + res: res{ + id: "id1", + want: &domain.ObjectDetails{ResourceOwner: "instance1"}, + }, + }, + { + name: "ok all set", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID( + "instance1", + instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + []string{openid.ScopeOpenID}, + true, + idp.Options{ + IsCreationAllowed: true, + IsLinkingAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + }, + )), + }, + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + ClientSecret: "clientSecret", + Scopes: []string{openid.ScopeOpenID}, + IsIDTokenMapping: true, + IDPOptions: idp.Options{ + IsCreationAllowed: true, + IsLinkingAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + }, + }, + }, + res: res{ + id: "id1", + want: &domain.ObjectDetails{ResourceOwner: "instance1"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + idpConfigEncryption: tt.fields.secretCrypto, + } + id, got, err := c.AddInstanceGenericOIDCProvider(tt.args.ctx, tt.args.provider) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.id, id) + assert.Equal(t, tt.res.want, got) + } + }) + } +} + +func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + secretCrypto crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + id string + provider GenericOIDCProvider + } + type res struct { + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid id", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + provider: GenericOIDCProvider{}, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-SAfd3", "")) + }, + }, + }, + { + "invalid name", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + id: "id1", + provider: GenericOIDCProvider{}, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Dvf4f", "")) + }, + }, + }, + { + "invalid issuer", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-BDfr3", "")) + }, + }, + }, + { + "invalid clientID", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Db3bs", "")) + }, + }, + }, + { + name: "not found", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + }, + }, + res: res{ + err: caos_errors.IsNotFound, + }, + }, + { + name: "no changes", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + nil, + false, + idp.Options{}, + )), + ), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + }, + }, + res: res{ + want: &domain.ObjectDetails{ResourceOwner: "instance1"}, + }, + }, + { + name: "change ok", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + nil, + false, + idp.Options{}, + )), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID( + "instance1", + func() eventstore.Command { + t := true + event, _ := instance.NewOIDCIDPChangedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, + "id1", + []idp.OIDCIDPChanges{ + idp.ChangeOIDCName("new name"), + idp.ChangeOIDCIssuer("new issuer"), + idp.ChangeOIDCClientID("clientID2"), + idp.ChangeOIDCClientSecret(&crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("newSecret"), + }), + idp.ChangeOIDCScopes([]string{"openid", "profile"}), + idp.ChangeOIDCIsIDTokenMapping(true), + idp.ChangeOIDCOptions(idp.OptionChanges{ + IsCreationAllowed: &t, + IsLinkingAllowed: &t, + IsAutoCreation: &t, + IsAutoUpdate: &t, + }), + }, + ) + return event + }(), + ), + }, + ), + ), + secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "instance1"), + id: "id1", + provider: GenericOIDCProvider{ + Name: "new name", + Issuer: "new issuer", + ClientID: "clientID2", + ClientSecret: "newSecret", + Scopes: []string{"openid", "profile"}, + IsIDTokenMapping: true, + IDPOptions: idp.Options{ + IsCreationAllowed: true, + IsLinkingAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ResourceOwner: "instance1"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idpConfigEncryption: tt.fields.secretCrypto, + } + got, err := c.UpdateInstanceGenericOIDCProvider(tt.args.ctx, tt.args.id, tt.args.provider) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.want, got) + } + }) + } +} + func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { type fields struct { eventstore *eventstore.Eventstore diff --git a/internal/command/org_idp.go b/internal/command/org_idp.go index 9a47c9e571..d9872be198 100644 --- a/internal/command/org_idp.go +++ b/internal/command/org_idp.go @@ -592,6 +592,7 @@ func (c *Commands) prepareAddOrgOIDCProvider(a *org.Aggregate, writeModel *OrgOI provider.ClientID, secret, provider.Scopes, + provider.IsIDTokenMapping, provider.IDPOptions, ), }, nil @@ -635,6 +636,7 @@ func (c *Commands) prepareUpdateOrgOIDCProvider(a *org.Aggregate, writeModel *Or provider.ClientSecret, c.idpConfigEncryption, provider.Scopes, + provider.IsIDTokenMapping, provider.IDPOptions, ) if err != nil || event == nil { diff --git a/internal/command/org_idp_model.go b/internal/command/org_idp_model.go index 10438ecd62..379a7eac66 100644 --- a/internal/command/org_idp_model.go +++ b/internal/command/org_idp_model.go @@ -168,6 +168,7 @@ func (wm *OrgOIDCIDPWriteModel) NewChangedEvent( clientSecretString string, secretCrypto crypto.Crypto, scopes []string, + idTokenMapping bool, options idp.Options, ) (*org.OIDCIDPChangedEvent, error) { @@ -178,6 +179,7 @@ func (wm *OrgOIDCIDPWriteModel) NewChangedEvent( clientSecretString, secretCrypto, scopes, + idTokenMapping, options, ) if err != nil || len(changes) == 0 { diff --git a/internal/command/org_idp_test.go b/internal/command/org_idp_test.go index 61568cb672..83d95025a4 100644 --- a/internal/command/org_idp_test.go +++ b/internal/command/org_idp_test.go @@ -7,6 +7,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + openid "github.com/zitadel/oidc/v2/pkg/oidc" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" @@ -648,6 +649,476 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { } } +func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + secretCrypto crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + resourceOwner string + provider GenericOIDCProvider + } + type res struct { + id string + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid name", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{}, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Sgtj5", "")) + }, + }, + }, + { + "invalid issuer", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{ + Name: "name", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Hz6zj", "")) + }, + }, + }, + { + "invalid clientID", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-fb5jm", "")) + }, + }, + }, + { + "invalid clientSecret", + fields{ + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Sfdf4", "")) + }, + }, + }, + { + name: "ok", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + expectPush( + eventPusherToEvents( + org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + nil, + false, + idp.Options{}, + )), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + ClientSecret: "clientSecret", + }, + }, + res: res{ + id: "id1", + want: &domain.ObjectDetails{ResourceOwner: "org1"}, + }, + }, + { + name: "ok all set", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + expectPush( + eventPusherToEvents( + org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + []string{openid.ScopeOpenID}, + true, + idp.Options{ + IsCreationAllowed: true, + IsLinkingAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + }, + )), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), + secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + ClientSecret: "clientSecret", + Scopes: []string{openid.ScopeOpenID}, + IsIDTokenMapping: true, + IDPOptions: idp.Options{ + IsCreationAllowed: true, + IsLinkingAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + }, + }, + }, + res: res{ + id: "id1", + want: &domain.ObjectDetails{ResourceOwner: "org1"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + idpConfigEncryption: tt.fields.secretCrypto, + } + id, got, err := c.AddOrgGenericOIDCProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.provider) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.id, id) + assert.Equal(t, tt.res.want, got) + } + }) + } +} + +func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + secretCrypto crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + resourceOwner string + id string + provider GenericOIDCProvider + } + type res struct { + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid id", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + provider: GenericOIDCProvider{}, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-SAfd3", "")) + }, + }, + }, + { + "invalid name", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + id: "id1", + provider: GenericOIDCProvider{}, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Dvf4f", "")) + }, + }, + }, + { + "invalid issuer", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-BDfr3", "")) + }, + }, + }, + { + "invalid clientID", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: context.Background(), + resourceOwner: "org1", + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + }, + }, + res{ + err: func(err error) bool { + return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Db3bs", "")) + }, + }, + }, + { + name: "not found", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + }, + args: args{ + ctx: context.Background(), + resourceOwner: "org1", + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + }, + }, + res: res{ + err: caos_errors.IsNotFound, + }, + }, + { + name: "no changes", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + nil, + false, + idp.Options{}, + )), + ), + ), + }, + args: args{ + ctx: context.Background(), + resourceOwner: "org1", + id: "id1", + provider: GenericOIDCProvider{ + Name: "name", + Issuer: "issuer", + ClientID: "clientID", + }, + }, + res: res{ + want: &domain.ObjectDetails{ResourceOwner: "org1"}, + }, + }, + { + name: "change ok", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, + "id1", + "name", + "issuer", + "clientID", + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("clientSecret"), + }, + nil, + false, + idp.Options{}, + )), + ), + expectPush( + eventPusherToEvents( + func() eventstore.Command { + t := true + event, _ := org.NewOIDCIDPChangedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, + "id1", + []idp.OIDCIDPChanges{ + idp.ChangeOIDCName("new name"), + idp.ChangeOIDCIssuer("new issuer"), + idp.ChangeOIDCClientID("clientID2"), + idp.ChangeOIDCClientSecret(&crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("newSecret"), + }), + idp.ChangeOIDCScopes([]string{"openid", "profile"}), + idp.ChangeOIDCIsIDTokenMapping(true), + idp.ChangeOIDCOptions(idp.OptionChanges{ + IsCreationAllowed: &t, + IsLinkingAllowed: &t, + IsAutoCreation: &t, + IsAutoUpdate: &t, + }), + }, + ) + return event + }(), + ), + ), + ), + secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + resourceOwner: "org1", + id: "id1", + provider: GenericOIDCProvider{ + Name: "new name", + Issuer: "new issuer", + ClientID: "clientID2", + ClientSecret: "newSecret", + Scopes: []string{"openid", "profile"}, + IsIDTokenMapping: true, + IDPOptions: idp.Options{ + IsCreationAllowed: true, + IsLinkingAllowed: true, + IsAutoCreation: true, + IsAutoUpdate: true, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ResourceOwner: "org1"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idpConfigEncryption: tt.fields.secretCrypto, + } + got, err := c.UpdateOrgGenericOIDCProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.want, got) + } + }) + } +} + func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { type fields struct { eventstore *eventstore.Eventstore diff --git a/internal/idp/providers/oidc/oidc.go b/internal/idp/providers/oidc/oidc.go index 2a0c305bdf..ecd37db7d8 100644 --- a/internal/idp/providers/oidc/oidc.go +++ b/internal/idp/providers/oidc/oidc.go @@ -20,6 +20,7 @@ type Provider struct { isCreationAllowed bool isAutoCreation bool isAutoUpdate bool + useIDToken bool userInfoMapper func(info oidc.UserInfo) idp.User authOptions []rp.AuthURLOpt } @@ -55,6 +56,13 @@ func WithAutoUpdate() ProviderOpts { } } +// WithIDTokenMapping enables that information to map the user is retrieved from the id_token and not the userinfo endpoint. +func WithIDTokenMapping() ProviderOpts { + return func(p *Provider) { + p.useIDToken = true + } +} + // WithRelyingPartyOption allows to set an additional [rp.Option] like [rp.WithPKCE]. func WithRelyingPartyOption(option rp.Option) ProviderOpts { return func(p *Provider) { diff --git a/internal/idp/providers/oidc/session.go b/internal/idp/providers/oidc/session.go index a2a668c0c8..fb1aa9549f 100644 --- a/internal/idp/providers/oidc/session.go +++ b/internal/idp/providers/oidc/session.go @@ -47,6 +47,9 @@ func (s *Session) FetchUser(ctx context.Context) (user idp.User, err error) { if err != nil { return nil, err } + if s.Provider.useIDToken { + info = s.Tokens.IDTokenClaims + } u := s.Provider.userInfoMapper(info) return u, nil } diff --git a/internal/query/idp_login_policy_link_test.go b/internal/query/idp_login_policy_link_test.go index 2a1802da64..609b5b0019 100644 --- a/internal/query/idp_login_policy_link_test.go +++ b/internal/query/idp_login_policy_link_test.go @@ -13,12 +13,12 @@ import ( var ( loginPolicyIDPLinksQuery = regexp.QuoteMeta(`SELECT projections.idp_login_policy_links4.idp_id,` + - ` projections.idp_templates3.name,` + - ` projections.idp_templates3.type,` + - ` projections.idp_templates3.owner_type,` + + ` projections.idp_templates4.name,` + + ` projections.idp_templates4.type,` + + ` projections.idp_templates4.owner_type,` + ` COUNT(*) OVER ()` + ` FROM projections.idp_login_policy_links4` + - ` LEFT JOIN projections.idp_templates3 ON projections.idp_login_policy_links4.idp_id = projections.idp_templates3.id AND projections.idp_login_policy_links4.instance_id = projections.idp_templates3.instance_id` + + ` LEFT JOIN projections.idp_templates4 ON projections.idp_login_policy_links4.idp_id = projections.idp_templates4.id AND projections.idp_login_policy_links4.instance_id = projections.idp_templates4.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) loginPolicyIDPLinksCols = []string{ "idp_id", diff --git a/internal/query/idp_template.go b/internal/query/idp_template.go index a5e2b3b69e..53190297f1 100644 --- a/internal/query/idp_template.go +++ b/internal/query/idp_template.go @@ -63,11 +63,12 @@ type OAuthIDPTemplate struct { } type OIDCIDPTemplate struct { - IDPID string - ClientID string - ClientSecret *crypto.CryptoValue - Issuer string - Scopes database.StringArray + IDPID string + ClientID string + ClientSecret *crypto.CryptoValue + Issuer string + Scopes database.StringArray + IsIDTokenMapping bool } type JWTIDPTemplate struct { @@ -278,6 +279,10 @@ var ( name: projection.OIDCScopesCol, table: oidcIdpTemplateTable, } + OIDCIDTokenMappingCol = Column{ + name: projection.OIDCIDTokenMappingCol, + table: oidcIdpTemplateTable, + } ) var ( @@ -722,6 +727,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se OIDCClientIDCol.identifier(), OIDCClientSecretCol.identifier(), OIDCScopesCol.identifier(), + OIDCIDTokenMappingCol.identifier(), // jwt JWTIDCol.identifier(), JWTIssuerCol.identifier(), @@ -818,6 +824,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se oidcClientID := sql.NullString{} oidcClientSecret := new(crypto.CryptoValue) oidcScopes := database.StringArray{} + oidcIDTokenMapping := sql.NullBool{} jwtID := sql.NullString{} jwtIssuer := sql.NullString{} @@ -913,6 +920,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se &oidcClientID, &oidcClientSecret, &oidcScopes, + &oidcIDTokenMapping, // jwt &jwtID, &jwtIssuer, @@ -1002,11 +1010,12 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se } if oidcID.Valid { idpTemplate.OIDCIDPTemplate = &OIDCIDPTemplate{ - IDPID: oidcID.String, - ClientID: oidcClientID.String, - ClientSecret: oidcClientSecret, - Issuer: oidcIssuer.String, - Scopes: oidcScopes, + IDPID: oidcID.String, + ClientID: oidcClientID.String, + ClientSecret: oidcClientSecret, + Issuer: oidcIssuer.String, + Scopes: oidcScopes, + IsIDTokenMapping: oidcIDTokenMapping.Bool, } } if jwtID.Valid { @@ -1135,6 +1144,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec OIDCClientIDCol.identifier(), OIDCClientSecretCol.identifier(), OIDCScopesCol.identifier(), + OIDCIDTokenMappingCol.identifier(), // jwt JWTIDCol.identifier(), JWTIssuerCol.identifier(), @@ -1235,6 +1245,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec oidcClientID := sql.NullString{} oidcClientSecret := new(crypto.CryptoValue) oidcScopes := database.StringArray{} + oidcIDTokenMapping := sql.NullBool{} jwtID := sql.NullString{} jwtIssuer := sql.NullString{} @@ -1330,6 +1341,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec &oidcClientID, &oidcClientSecret, &oidcScopes, + &oidcIDTokenMapping, // jwt &jwtID, &jwtIssuer, @@ -1418,11 +1430,12 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec } if oidcID.Valid { idpTemplate.OIDCIDPTemplate = &OIDCIDPTemplate{ - IDPID: oidcID.String, - ClientID: oidcClientID.String, - ClientSecret: oidcClientSecret, - Issuer: oidcIssuer.String, - Scopes: oidcScopes, + IDPID: oidcID.String, + ClientID: oidcClientID.String, + ClientSecret: oidcClientSecret, + Issuer: oidcIssuer.String, + Scopes: oidcScopes, + IsIDTokenMapping: oidcIDTokenMapping.Bool, } } if jwtID.Valid { diff --git a/internal/query/idp_template_test.go b/internal/query/idp_template_test.go index d7b93293ba..e3147116fe 100644 --- a/internal/query/idp_template_test.go +++ b/internal/query/idp_template_test.go @@ -15,110 +15,111 @@ import ( ) var ( - idpTemplateQuery = `SELECT projections.idp_templates3.id,` + - ` projections.idp_templates3.resource_owner,` + - ` projections.idp_templates3.creation_date,` + - ` projections.idp_templates3.change_date,` + - ` projections.idp_templates3.sequence,` + - ` projections.idp_templates3.state,` + - ` projections.idp_templates3.name,` + - ` projections.idp_templates3.type,` + - ` projections.idp_templates3.owner_type,` + - ` projections.idp_templates3.is_creation_allowed,` + - ` projections.idp_templates3.is_linking_allowed,` + - ` projections.idp_templates3.is_auto_creation,` + - ` projections.idp_templates3.is_auto_update,` + + idpTemplateQuery = `SELECT projections.idp_templates4.id,` + + ` projections.idp_templates4.resource_owner,` + + ` projections.idp_templates4.creation_date,` + + ` projections.idp_templates4.change_date,` + + ` projections.idp_templates4.sequence,` + + ` projections.idp_templates4.state,` + + ` projections.idp_templates4.name,` + + ` projections.idp_templates4.type,` + + ` projections.idp_templates4.owner_type,` + + ` projections.idp_templates4.is_creation_allowed,` + + ` projections.idp_templates4.is_linking_allowed,` + + ` projections.idp_templates4.is_auto_creation,` + + ` projections.idp_templates4.is_auto_update,` + // oauth - ` projections.idp_templates3_oauth2.idp_id,` + - ` projections.idp_templates3_oauth2.client_id,` + - ` projections.idp_templates3_oauth2.client_secret,` + - ` projections.idp_templates3_oauth2.authorization_endpoint,` + - ` projections.idp_templates3_oauth2.token_endpoint,` + - ` projections.idp_templates3_oauth2.user_endpoint,` + - ` projections.idp_templates3_oauth2.scopes,` + - ` projections.idp_templates3_oauth2.id_attribute,` + + ` projections.idp_templates4_oauth2.idp_id,` + + ` projections.idp_templates4_oauth2.client_id,` + + ` projections.idp_templates4_oauth2.client_secret,` + + ` projections.idp_templates4_oauth2.authorization_endpoint,` + + ` projections.idp_templates4_oauth2.token_endpoint,` + + ` projections.idp_templates4_oauth2.user_endpoint,` + + ` projections.idp_templates4_oauth2.scopes,` + + ` projections.idp_templates4_oauth2.id_attribute,` + // oidc - ` projections.idp_templates3_oidc.idp_id,` + - ` projections.idp_templates3_oidc.issuer,` + - ` projections.idp_templates3_oidc.client_id,` + - ` projections.idp_templates3_oidc.client_secret,` + - ` projections.idp_templates3_oidc.scopes,` + + ` projections.idp_templates4_oidc.idp_id,` + + ` projections.idp_templates4_oidc.issuer,` + + ` projections.idp_templates4_oidc.client_id,` + + ` projections.idp_templates4_oidc.client_secret,` + + ` projections.idp_templates4_oidc.scopes,` + + ` projections.idp_templates4_oidc.id_token_mapping,` + // jwt - ` projections.idp_templates3_jwt.idp_id,` + - ` projections.idp_templates3_jwt.issuer,` + - ` projections.idp_templates3_jwt.jwt_endpoint,` + - ` projections.idp_templates3_jwt.keys_endpoint,` + - ` projections.idp_templates3_jwt.header_name,` + + ` projections.idp_templates4_jwt.idp_id,` + + ` projections.idp_templates4_jwt.issuer,` + + ` projections.idp_templates4_jwt.jwt_endpoint,` + + ` projections.idp_templates4_jwt.keys_endpoint,` + + ` projections.idp_templates4_jwt.header_name,` + // azure - ` projections.idp_templates3_azure.idp_id,` + - ` projections.idp_templates3_azure.client_id,` + - ` projections.idp_templates3_azure.client_secret,` + - ` projections.idp_templates3_azure.scopes,` + - ` projections.idp_templates3_azure.tenant,` + - ` projections.idp_templates3_azure.is_email_verified,` + + ` projections.idp_templates4_azure.idp_id,` + + ` projections.idp_templates4_azure.client_id,` + + ` projections.idp_templates4_azure.client_secret,` + + ` projections.idp_templates4_azure.scopes,` + + ` projections.idp_templates4_azure.tenant,` + + ` projections.idp_templates4_azure.is_email_verified,` + // github - ` projections.idp_templates3_github.idp_id,` + - ` projections.idp_templates3_github.client_id,` + - ` projections.idp_templates3_github.client_secret,` + - ` projections.idp_templates3_github.scopes,` + + ` projections.idp_templates4_github.idp_id,` + + ` projections.idp_templates4_github.client_id,` + + ` projections.idp_templates4_github.client_secret,` + + ` projections.idp_templates4_github.scopes,` + // github enterprise - ` projections.idp_templates3_github_enterprise.idp_id,` + - ` projections.idp_templates3_github_enterprise.client_id,` + - ` projections.idp_templates3_github_enterprise.client_secret,` + - ` projections.idp_templates3_github_enterprise.authorization_endpoint,` + - ` projections.idp_templates3_github_enterprise.token_endpoint,` + - ` projections.idp_templates3_github_enterprise.user_endpoint,` + - ` projections.idp_templates3_github_enterprise.scopes,` + + ` projections.idp_templates4_github_enterprise.idp_id,` + + ` projections.idp_templates4_github_enterprise.client_id,` + + ` projections.idp_templates4_github_enterprise.client_secret,` + + ` projections.idp_templates4_github_enterprise.authorization_endpoint,` + + ` projections.idp_templates4_github_enterprise.token_endpoint,` + + ` projections.idp_templates4_github_enterprise.user_endpoint,` + + ` projections.idp_templates4_github_enterprise.scopes,` + // gitlab - ` projections.idp_templates3_gitlab.idp_id,` + - ` projections.idp_templates3_gitlab.client_id,` + - ` projections.idp_templates3_gitlab.client_secret,` + - ` projections.idp_templates3_gitlab.scopes,` + + ` projections.idp_templates4_gitlab.idp_id,` + + ` projections.idp_templates4_gitlab.client_id,` + + ` projections.idp_templates4_gitlab.client_secret,` + + ` projections.idp_templates4_gitlab.scopes,` + // gitlab self hosted - ` projections.idp_templates3_gitlab_self_hosted.idp_id,` + - ` projections.idp_templates3_gitlab_self_hosted.issuer,` + - ` projections.idp_templates3_gitlab_self_hosted.client_id,` + - ` projections.idp_templates3_gitlab_self_hosted.client_secret,` + - ` projections.idp_templates3_gitlab_self_hosted.scopes,` + + ` projections.idp_templates4_gitlab_self_hosted.idp_id,` + + ` projections.idp_templates4_gitlab_self_hosted.issuer,` + + ` projections.idp_templates4_gitlab_self_hosted.client_id,` + + ` projections.idp_templates4_gitlab_self_hosted.client_secret,` + + ` projections.idp_templates4_gitlab_self_hosted.scopes,` + // google - ` projections.idp_templates3_google.idp_id,` + - ` projections.idp_templates3_google.client_id,` + - ` projections.idp_templates3_google.client_secret,` + - ` projections.idp_templates3_google.scopes,` + + ` projections.idp_templates4_google.idp_id,` + + ` projections.idp_templates4_google.client_id,` + + ` projections.idp_templates4_google.client_secret,` + + ` projections.idp_templates4_google.scopes,` + // ldap - ` projections.idp_templates3_ldap.idp_id,` + - ` projections.idp_templates3_ldap.host,` + - ` projections.idp_templates3_ldap.port,` + - ` projections.idp_templates3_ldap.tls,` + - ` projections.idp_templates3_ldap.base_dn,` + - ` projections.idp_templates3_ldap.user_object_class,` + - ` projections.idp_templates3_ldap.user_unique_attribute,` + - ` projections.idp_templates3_ldap.admin,` + - ` projections.idp_templates3_ldap.password,` + - ` projections.idp_templates3_ldap.id_attribute,` + - ` projections.idp_templates3_ldap.first_name_attribute,` + - ` projections.idp_templates3_ldap.last_name_attribute,` + - ` projections.idp_templates3_ldap.display_name_attribute,` + - ` projections.idp_templates3_ldap.nick_name_attribute,` + - ` projections.idp_templates3_ldap.preferred_username_attribute,` + - ` projections.idp_templates3_ldap.email_attribute,` + - ` projections.idp_templates3_ldap.email_verified,` + - ` projections.idp_templates3_ldap.phone_attribute,` + - ` projections.idp_templates3_ldap.phone_verified_attribute,` + - ` projections.idp_templates3_ldap.preferred_language_attribute,` + - ` projections.idp_templates3_ldap.avatar_url_attribute,` + - ` projections.idp_templates3_ldap.profile_attribute` + - ` FROM projections.idp_templates3` + - ` LEFT JOIN projections.idp_templates3_oauth2 ON projections.idp_templates3.id = projections.idp_templates3_oauth2.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_oauth2.instance_id` + - ` LEFT JOIN projections.idp_templates3_oidc ON projections.idp_templates3.id = projections.idp_templates3_oidc.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_oidc.instance_id` + - ` LEFT JOIN projections.idp_templates3_jwt ON projections.idp_templates3.id = projections.idp_templates3_jwt.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_jwt.instance_id` + - ` LEFT JOIN projections.idp_templates3_azure ON projections.idp_templates3.id = projections.idp_templates3_azure.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_azure.instance_id` + - ` LEFT JOIN projections.idp_templates3_github ON projections.idp_templates3.id = projections.idp_templates3_github.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_github.instance_id` + - ` LEFT JOIN projections.idp_templates3_github_enterprise ON projections.idp_templates3.id = projections.idp_templates3_github_enterprise.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_github_enterprise.instance_id` + - ` LEFT JOIN projections.idp_templates3_gitlab ON projections.idp_templates3.id = projections.idp_templates3_gitlab.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_gitlab.instance_id` + - ` LEFT JOIN projections.idp_templates3_gitlab_self_hosted ON projections.idp_templates3.id = projections.idp_templates3_gitlab_self_hosted.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_gitlab_self_hosted.instance_id` + - ` LEFT JOIN projections.idp_templates3_google ON projections.idp_templates3.id = projections.idp_templates3_google.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_google.instance_id` + - ` LEFT JOIN projections.idp_templates3_ldap ON projections.idp_templates3.id = projections.idp_templates3_ldap.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_ldap.instance_id` + + ` projections.idp_templates4_ldap.idp_id,` + + ` projections.idp_templates4_ldap.host,` + + ` projections.idp_templates4_ldap.port,` + + ` projections.idp_templates4_ldap.tls,` + + ` projections.idp_templates4_ldap.base_dn,` + + ` projections.idp_templates4_ldap.user_object_class,` + + ` projections.idp_templates4_ldap.user_unique_attribute,` + + ` projections.idp_templates4_ldap.admin,` + + ` projections.idp_templates4_ldap.password,` + + ` projections.idp_templates4_ldap.id_attribute,` + + ` projections.idp_templates4_ldap.first_name_attribute,` + + ` projections.idp_templates4_ldap.last_name_attribute,` + + ` projections.idp_templates4_ldap.display_name_attribute,` + + ` projections.idp_templates4_ldap.nick_name_attribute,` + + ` projections.idp_templates4_ldap.preferred_username_attribute,` + + ` projections.idp_templates4_ldap.email_attribute,` + + ` projections.idp_templates4_ldap.email_verified,` + + ` projections.idp_templates4_ldap.phone_attribute,` + + ` projections.idp_templates4_ldap.phone_verified_attribute,` + + ` projections.idp_templates4_ldap.preferred_language_attribute,` + + ` projections.idp_templates4_ldap.avatar_url_attribute,` + + ` projections.idp_templates4_ldap.profile_attribute` + + ` FROM projections.idp_templates4` + + ` LEFT JOIN projections.idp_templates4_oauth2 ON projections.idp_templates4.id = projections.idp_templates4_oauth2.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oauth2.instance_id` + + ` LEFT JOIN projections.idp_templates4_oidc ON projections.idp_templates4.id = projections.idp_templates4_oidc.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oidc.instance_id` + + ` LEFT JOIN projections.idp_templates4_jwt ON projections.idp_templates4.id = projections.idp_templates4_jwt.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_jwt.instance_id` + + ` LEFT JOIN projections.idp_templates4_azure ON projections.idp_templates4.id = projections.idp_templates4_azure.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_azure.instance_id` + + ` LEFT JOIN projections.idp_templates4_github ON projections.idp_templates4.id = projections.idp_templates4_github.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_github.instance_id` + + ` LEFT JOIN projections.idp_templates4_github_enterprise ON projections.idp_templates4.id = projections.idp_templates4_github_enterprise.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_github_enterprise.instance_id` + + ` LEFT JOIN projections.idp_templates4_gitlab ON projections.idp_templates4.id = projections.idp_templates4_gitlab.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab.instance_id` + + ` LEFT JOIN projections.idp_templates4_gitlab_self_hosted ON projections.idp_templates4.id = projections.idp_templates4_gitlab_self_hosted.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab_self_hosted.instance_id` + + ` LEFT JOIN projections.idp_templates4_google ON projections.idp_templates4.id = projections.idp_templates4_google.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_google.instance_id` + + ` LEFT JOIN projections.idp_templates4_ldap ON projections.idp_templates4.id = projections.idp_templates4_ldap.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_ldap.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` idpTemplateCols = []string{ "id", @@ -149,6 +150,7 @@ var ( "client_id", "client_secret", "scopes", + "id_token_mapping", // jwt "idp_id", "issuer", @@ -215,111 +217,112 @@ var ( "avatar_url_attribute", "profile_attribute", } - idpTemplatesQuery = `SELECT projections.idp_templates3.id,` + - ` projections.idp_templates3.resource_owner,` + - ` projections.idp_templates3.creation_date,` + - ` projections.idp_templates3.change_date,` + - ` projections.idp_templates3.sequence,` + - ` projections.idp_templates3.state,` + - ` projections.idp_templates3.name,` + - ` projections.idp_templates3.type,` + - ` projections.idp_templates3.owner_type,` + - ` projections.idp_templates3.is_creation_allowed,` + - ` projections.idp_templates3.is_linking_allowed,` + - ` projections.idp_templates3.is_auto_creation,` + - ` projections.idp_templates3.is_auto_update,` + + idpTemplatesQuery = `SELECT projections.idp_templates4.id,` + + ` projections.idp_templates4.resource_owner,` + + ` projections.idp_templates4.creation_date,` + + ` projections.idp_templates4.change_date,` + + ` projections.idp_templates4.sequence,` + + ` projections.idp_templates4.state,` + + ` projections.idp_templates4.name,` + + ` projections.idp_templates4.type,` + + ` projections.idp_templates4.owner_type,` + + ` projections.idp_templates4.is_creation_allowed,` + + ` projections.idp_templates4.is_linking_allowed,` + + ` projections.idp_templates4.is_auto_creation,` + + ` projections.idp_templates4.is_auto_update,` + // oauth - ` projections.idp_templates3_oauth2.idp_id,` + - ` projections.idp_templates3_oauth2.client_id,` + - ` projections.idp_templates3_oauth2.client_secret,` + - ` projections.idp_templates3_oauth2.authorization_endpoint,` + - ` projections.idp_templates3_oauth2.token_endpoint,` + - ` projections.idp_templates3_oauth2.user_endpoint,` + - ` projections.idp_templates3_oauth2.scopes,` + - ` projections.idp_templates3_oauth2.id_attribute,` + + ` projections.idp_templates4_oauth2.idp_id,` + + ` projections.idp_templates4_oauth2.client_id,` + + ` projections.idp_templates4_oauth2.client_secret,` + + ` projections.idp_templates4_oauth2.authorization_endpoint,` + + ` projections.idp_templates4_oauth2.token_endpoint,` + + ` projections.idp_templates4_oauth2.user_endpoint,` + + ` projections.idp_templates4_oauth2.scopes,` + + ` projections.idp_templates4_oauth2.id_attribute,` + // oidc - ` projections.idp_templates3_oidc.idp_id,` + - ` projections.idp_templates3_oidc.issuer,` + - ` projections.idp_templates3_oidc.client_id,` + - ` projections.idp_templates3_oidc.client_secret,` + - ` projections.idp_templates3_oidc.scopes,` + + ` projections.idp_templates4_oidc.idp_id,` + + ` projections.idp_templates4_oidc.issuer,` + + ` projections.idp_templates4_oidc.client_id,` + + ` projections.idp_templates4_oidc.client_secret,` + + ` projections.idp_templates4_oidc.scopes,` + + ` projections.idp_templates4_oidc.id_token_mapping,` + // jwt - ` projections.idp_templates3_jwt.idp_id,` + - ` projections.idp_templates3_jwt.issuer,` + - ` projections.idp_templates3_jwt.jwt_endpoint,` + - ` projections.idp_templates3_jwt.keys_endpoint,` + - ` projections.idp_templates3_jwt.header_name,` + + ` projections.idp_templates4_jwt.idp_id,` + + ` projections.idp_templates4_jwt.issuer,` + + ` projections.idp_templates4_jwt.jwt_endpoint,` + + ` projections.idp_templates4_jwt.keys_endpoint,` + + ` projections.idp_templates4_jwt.header_name,` + // azure - ` projections.idp_templates3_azure.idp_id,` + - ` projections.idp_templates3_azure.client_id,` + - ` projections.idp_templates3_azure.client_secret,` + - ` projections.idp_templates3_azure.scopes,` + - ` projections.idp_templates3_azure.tenant,` + - ` projections.idp_templates3_azure.is_email_verified,` + + ` projections.idp_templates4_azure.idp_id,` + + ` projections.idp_templates4_azure.client_id,` + + ` projections.idp_templates4_azure.client_secret,` + + ` projections.idp_templates4_azure.scopes,` + + ` projections.idp_templates4_azure.tenant,` + + ` projections.idp_templates4_azure.is_email_verified,` + // github - ` projections.idp_templates3_github.idp_id,` + - ` projections.idp_templates3_github.client_id,` + - ` projections.idp_templates3_github.client_secret,` + - ` projections.idp_templates3_github.scopes,` + + ` projections.idp_templates4_github.idp_id,` + + ` projections.idp_templates4_github.client_id,` + + ` projections.idp_templates4_github.client_secret,` + + ` projections.idp_templates4_github.scopes,` + // github enterprise - ` projections.idp_templates3_github_enterprise.idp_id,` + - ` projections.idp_templates3_github_enterprise.client_id,` + - ` projections.idp_templates3_github_enterprise.client_secret,` + - ` projections.idp_templates3_github_enterprise.authorization_endpoint,` + - ` projections.idp_templates3_github_enterprise.token_endpoint,` + - ` projections.idp_templates3_github_enterprise.user_endpoint,` + - ` projections.idp_templates3_github_enterprise.scopes,` + + ` projections.idp_templates4_github_enterprise.idp_id,` + + ` projections.idp_templates4_github_enterprise.client_id,` + + ` projections.idp_templates4_github_enterprise.client_secret,` + + ` projections.idp_templates4_github_enterprise.authorization_endpoint,` + + ` projections.idp_templates4_github_enterprise.token_endpoint,` + + ` projections.idp_templates4_github_enterprise.user_endpoint,` + + ` projections.idp_templates4_github_enterprise.scopes,` + // gitlab - ` projections.idp_templates3_gitlab.idp_id,` + - ` projections.idp_templates3_gitlab.client_id,` + - ` projections.idp_templates3_gitlab.client_secret,` + - ` projections.idp_templates3_gitlab.scopes,` + + ` projections.idp_templates4_gitlab.idp_id,` + + ` projections.idp_templates4_gitlab.client_id,` + + ` projections.idp_templates4_gitlab.client_secret,` + + ` projections.idp_templates4_gitlab.scopes,` + // gitlab self hosted - ` projections.idp_templates3_gitlab_self_hosted.idp_id,` + - ` projections.idp_templates3_gitlab_self_hosted.issuer,` + - ` projections.idp_templates3_gitlab_self_hosted.client_id,` + - ` projections.idp_templates3_gitlab_self_hosted.client_secret,` + - ` projections.idp_templates3_gitlab_self_hosted.scopes,` + + ` projections.idp_templates4_gitlab_self_hosted.idp_id,` + + ` projections.idp_templates4_gitlab_self_hosted.issuer,` + + ` projections.idp_templates4_gitlab_self_hosted.client_id,` + + ` projections.idp_templates4_gitlab_self_hosted.client_secret,` + + ` projections.idp_templates4_gitlab_self_hosted.scopes,` + // google - ` projections.idp_templates3_google.idp_id,` + - ` projections.idp_templates3_google.client_id,` + - ` projections.idp_templates3_google.client_secret,` + - ` projections.idp_templates3_google.scopes,` + + ` projections.idp_templates4_google.idp_id,` + + ` projections.idp_templates4_google.client_id,` + + ` projections.idp_templates4_google.client_secret,` + + ` projections.idp_templates4_google.scopes,` + // ldap - ` projections.idp_templates3_ldap.idp_id,` + - ` projections.idp_templates3_ldap.host,` + - ` projections.idp_templates3_ldap.port,` + - ` projections.idp_templates3_ldap.tls,` + - ` projections.idp_templates3_ldap.base_dn,` + - ` projections.idp_templates3_ldap.user_object_class,` + - ` projections.idp_templates3_ldap.user_unique_attribute,` + - ` projections.idp_templates3_ldap.admin,` + - ` projections.idp_templates3_ldap.password,` + - ` projections.idp_templates3_ldap.id_attribute,` + - ` projections.idp_templates3_ldap.first_name_attribute,` + - ` projections.idp_templates3_ldap.last_name_attribute,` + - ` projections.idp_templates3_ldap.display_name_attribute,` + - ` projections.idp_templates3_ldap.nick_name_attribute,` + - ` projections.idp_templates3_ldap.preferred_username_attribute,` + - ` projections.idp_templates3_ldap.email_attribute,` + - ` projections.idp_templates3_ldap.email_verified,` + - ` projections.idp_templates3_ldap.phone_attribute,` + - ` projections.idp_templates3_ldap.phone_verified_attribute,` + - ` projections.idp_templates3_ldap.preferred_language_attribute,` + - ` projections.idp_templates3_ldap.avatar_url_attribute,` + - ` projections.idp_templates3_ldap.profile_attribute,` + + ` projections.idp_templates4_ldap.idp_id,` + + ` projections.idp_templates4_ldap.host,` + + ` projections.idp_templates4_ldap.port,` + + ` projections.idp_templates4_ldap.tls,` + + ` projections.idp_templates4_ldap.base_dn,` + + ` projections.idp_templates4_ldap.user_object_class,` + + ` projections.idp_templates4_ldap.user_unique_attribute,` + + ` projections.idp_templates4_ldap.admin,` + + ` projections.idp_templates4_ldap.password,` + + ` projections.idp_templates4_ldap.id_attribute,` + + ` projections.idp_templates4_ldap.first_name_attribute,` + + ` projections.idp_templates4_ldap.last_name_attribute,` + + ` projections.idp_templates4_ldap.display_name_attribute,` + + ` projections.idp_templates4_ldap.nick_name_attribute,` + + ` projections.idp_templates4_ldap.preferred_username_attribute,` + + ` projections.idp_templates4_ldap.email_attribute,` + + ` projections.idp_templates4_ldap.email_verified,` + + ` projections.idp_templates4_ldap.phone_attribute,` + + ` projections.idp_templates4_ldap.phone_verified_attribute,` + + ` projections.idp_templates4_ldap.preferred_language_attribute,` + + ` projections.idp_templates4_ldap.avatar_url_attribute,` + + ` projections.idp_templates4_ldap.profile_attribute,` + ` COUNT(*) OVER ()` + - ` FROM projections.idp_templates3` + - ` LEFT JOIN projections.idp_templates3_oauth2 ON projections.idp_templates3.id = projections.idp_templates3_oauth2.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_oauth2.instance_id` + - ` LEFT JOIN projections.idp_templates3_oidc ON projections.idp_templates3.id = projections.idp_templates3_oidc.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_oidc.instance_id` + - ` LEFT JOIN projections.idp_templates3_jwt ON projections.idp_templates3.id = projections.idp_templates3_jwt.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_jwt.instance_id` + - ` LEFT JOIN projections.idp_templates3_azure ON projections.idp_templates3.id = projections.idp_templates3_azure.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_azure.instance_id` + - ` LEFT JOIN projections.idp_templates3_github ON projections.idp_templates3.id = projections.idp_templates3_github.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_github.instance_id` + - ` LEFT JOIN projections.idp_templates3_github_enterprise ON projections.idp_templates3.id = projections.idp_templates3_github_enterprise.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_github_enterprise.instance_id` + - ` LEFT JOIN projections.idp_templates3_gitlab ON projections.idp_templates3.id = projections.idp_templates3_gitlab.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_gitlab.instance_id` + - ` LEFT JOIN projections.idp_templates3_gitlab_self_hosted ON projections.idp_templates3.id = projections.idp_templates3_gitlab_self_hosted.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_gitlab_self_hosted.instance_id` + - ` LEFT JOIN projections.idp_templates3_google ON projections.idp_templates3.id = projections.idp_templates3_google.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_google.instance_id` + - ` LEFT JOIN projections.idp_templates3_ldap ON projections.idp_templates3.id = projections.idp_templates3_ldap.idp_id AND projections.idp_templates3.instance_id = projections.idp_templates3_ldap.instance_id` + + ` FROM projections.idp_templates4` + + ` LEFT JOIN projections.idp_templates4_oauth2 ON projections.idp_templates4.id = projections.idp_templates4_oauth2.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oauth2.instance_id` + + ` LEFT JOIN projections.idp_templates4_oidc ON projections.idp_templates4.id = projections.idp_templates4_oidc.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oidc.instance_id` + + ` LEFT JOIN projections.idp_templates4_jwt ON projections.idp_templates4.id = projections.idp_templates4_jwt.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_jwt.instance_id` + + ` LEFT JOIN projections.idp_templates4_azure ON projections.idp_templates4.id = projections.idp_templates4_azure.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_azure.instance_id` + + ` LEFT JOIN projections.idp_templates4_github ON projections.idp_templates4.id = projections.idp_templates4_github.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_github.instance_id` + + ` LEFT JOIN projections.idp_templates4_github_enterprise ON projections.idp_templates4.id = projections.idp_templates4_github_enterprise.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_github_enterprise.instance_id` + + ` LEFT JOIN projections.idp_templates4_gitlab ON projections.idp_templates4.id = projections.idp_templates4_gitlab.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab.instance_id` + + ` LEFT JOIN projections.idp_templates4_gitlab_self_hosted ON projections.idp_templates4.id = projections.idp_templates4_gitlab_self_hosted.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab_self_hosted.instance_id` + + ` LEFT JOIN projections.idp_templates4_google ON projections.idp_templates4.id = projections.idp_templates4_google.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_google.instance_id` + + ` LEFT JOIN projections.idp_templates4_ldap ON projections.idp_templates4.id = projections.idp_templates4_ldap.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_ldap.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` idpTemplatesCols = []string{ "id", @@ -350,6 +353,7 @@ var ( "client_id", "client_secret", "scopes", + "id_token_mapping", // jwt "idp_id", "issuer", @@ -484,6 +488,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -614,6 +619,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { "client_id", nil, database.StringArray{"profile"}, + true, // jwt nil, nil, @@ -697,11 +703,12 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { IsAutoCreation: true, IsAutoUpdate: true, OIDCIDPTemplate: &OIDCIDPTemplate{ - IDPID: "idp-id", - Issuer: "issuer", - ClientID: "client_id", - ClientSecret: nil, - Scopes: []string{"profile"}, + IDPID: "idp-id", + Issuer: "issuer", + ClientID: "client_id", + ClientSecret: nil, + Scopes: []string{"profile"}, + IsIDTokenMapping: true, }, }, }, @@ -741,6 +748,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt "idp-id", "issuer", @@ -868,6 +876,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -994,6 +1003,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1120,6 +1130,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1247,6 +1258,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1373,6 +1385,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1518,6 +1531,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1674,6 +1688,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1828,6 +1843,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -1957,6 +1973,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -2052,6 +2069,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -2147,6 +2165,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt nil, nil, @@ -2242,6 +2261,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { "client_id", nil, database.StringArray{"profile"}, + true, // jwt nil, nil, @@ -2337,6 +2357,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, // jwt "idp-id-jwt", "issuer", @@ -2513,11 +2534,12 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { IsAutoCreation: true, IsAutoUpdate: true, OIDCIDPTemplate: &OIDCIDPTemplate{ - IDPID: "idp-id-oidc", - Issuer: "issuer", - ClientID: "client_id", - ClientSecret: nil, - Scopes: []string{"profile"}, + IDPID: "idp-id-oidc", + Issuer: "issuer", + ClientID: "client_id", + ClientSecret: nil, + Scopes: []string{"profile"}, + IsIDTokenMapping: true, }, }, { diff --git a/internal/query/idp_user_link_test.go b/internal/query/idp_user_link_test.go index f42736a792..35fce2aabd 100644 --- a/internal/query/idp_user_link_test.go +++ b/internal/query/idp_user_link_test.go @@ -14,14 +14,14 @@ import ( var ( idpUserLinksQuery = regexp.QuoteMeta(`SELECT projections.idp_user_links3.idp_id,` + ` projections.idp_user_links3.user_id,` + - ` projections.idp_templates3.name,` + + ` projections.idp_templates4.name,` + ` projections.idp_user_links3.external_user_id,` + ` projections.idp_user_links3.display_name,` + - ` projections.idp_templates3.type,` + + ` projections.idp_templates4.type,` + ` projections.idp_user_links3.resource_owner,` + ` COUNT(*) OVER ()` + ` FROM projections.idp_user_links3` + - ` LEFT JOIN projections.idp_templates3 ON projections.idp_user_links3.idp_id = projections.idp_templates3.id AND projections.idp_user_links3.instance_id = projections.idp_templates3.instance_id` + + ` LEFT JOIN projections.idp_templates4 ON projections.idp_user_links3.idp_id = projections.idp_templates4.id AND projections.idp_user_links3.instance_id = projections.idp_templates4.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) idpUserLinksCols = []string{ "idp_id", diff --git a/internal/query/projection/idp_template.go b/internal/query/projection/idp_template.go index 3f6d43dadf..98011cdca4 100644 --- a/internal/query/projection/idp_template.go +++ b/internal/query/projection/idp_template.go @@ -17,7 +17,7 @@ import ( ) const ( - IDPTemplateTable = "projections.idp_templates3" + IDPTemplateTable = "projections.idp_templates4" IDPTemplateOAuthTable = IDPTemplateTable + "_" + IDPTemplateOAuthSuffix IDPTemplateOIDCTable = IDPTemplateTable + "_" + IDPTemplateOIDCSuffix IDPTemplateJWTTable = IDPTemplateTable + "_" + IDPTemplateJWTSuffix @@ -66,12 +66,13 @@ const ( OAuthScopesCol = "scopes" OAuthIDAttributeCol = "id_attribute" - OIDCIDCol = "idp_id" - OIDCInstanceIDCol = "instance_id" - OIDCIssuerCol = "issuer" - OIDCClientIDCol = "client_id" - OIDCClientSecretCol = "client_secret" - OIDCScopesCol = "scopes" + OIDCIDCol = "idp_id" + OIDCInstanceIDCol = "instance_id" + OIDCIssuerCol = "issuer" + OIDCClientIDCol = "client_id" + OIDCClientSecretCol = "client_secret" + OIDCScopesCol = "scopes" + OIDCIDTokenMappingCol = "id_token_mapping" JWTIDCol = "idp_id" JWTInstanceIDCol = "instance_id" @@ -199,6 +200,7 @@ func newIDPTemplateProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(OIDCClientIDCol, crdb.ColumnTypeText), crdb.NewColumn(OIDCClientSecretCol, crdb.ColumnTypeJSONB), crdb.NewColumn(OIDCScopesCol, crdb.ColumnTypeTextArray, crdb.Nullable()), + crdb.NewColumn(OIDCIDTokenMappingCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(OIDCInstanceIDCol, OIDCIDCol), IDPTemplateOIDCSuffix, @@ -695,6 +697,7 @@ func (p *idpTemplateProjection) reduceOIDCIDPAdded(event eventstore.Event) (*han handler.NewCol(OIDCClientIDCol, idpEvent.ClientID), handler.NewCol(OIDCClientSecretCol, idpEvent.ClientSecret), handler.NewCol(OIDCScopesCol, database.StringArray(idpEvent.Scopes)), + handler.NewCol(OIDCIDTokenMappingCol, idpEvent.IsIDTokenMapping), }, crdb.WithTableSuffix(IDPTemplateOIDCSuffix), ), @@ -931,6 +934,7 @@ func (p *idpTemplateProjection) reduceOldOIDCConfigAdded(event eventstore.Event) handler.NewCol(OIDCClientIDCol, idpEvent.ClientID), handler.NewCol(OIDCClientSecretCol, idpEvent.ClientSecret), handler.NewCol(OIDCScopesCol, database.StringArray(idpEvent.Scopes)), + handler.NewCol(OIDCIDTokenMappingCol, true), }, crdb.WithTableSuffix(IDPTemplateOIDCSuffix), ), @@ -1831,6 +1835,9 @@ func reduceOIDCIDPChangedColumns(idpEvent idp.OIDCIDPChangedEvent) []handler.Col if idpEvent.Scopes != nil { oidcCols = append(oidcCols, handler.NewCol(OIDCScopesCol, database.StringArray(idpEvent.Scopes))) } + if idpEvent.IsIDTokenMapping != nil { + oidcCols = append(oidcCols, handler.NewCol(OIDCIDTokenMappingCol, *idpEvent.IsIDTokenMapping)) + } return oidcCols } diff --git a/internal/query/projection/idp_template_test.go b/internal/query/projection/idp_template_test.go index f453575b33..6e58a76edc 100644 --- a/internal/query/projection/idp_template_test.go +++ b/internal/query/projection/idp_template_test.go @@ -14,11 +14,11 @@ import ( ) var ( - idpTemplateInsertStmt = `INSERT INTO projections.idp_templates3` + + idpTemplateInsertStmt = `INSERT INTO projections.idp_templates4` + ` (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, owner_type, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update)` + ` VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)` - idpTemplateUpdateMinimalStmt = `UPDATE projections.idp_templates3 SET (is_creation_allowed, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)` - idpTemplateUpdateStmt = `UPDATE projections.idp_templates3 SET (name, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update, change_date, sequence)` + + idpTemplateUpdateMinimalStmt = `UPDATE projections.idp_templates4 SET (is_creation_allowed, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)` + idpTemplateUpdateStmt = `UPDATE projections.idp_templates4 SET (name, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update, change_date, sequence)` + ` = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)` ) @@ -50,7 +50,7 @@ func TestIDPTemplateProjection_reducesRemove(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_templates3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.idp_templates4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -76,7 +76,7 @@ func TestIDPTemplateProjection_reducesRemove(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -108,7 +108,7 @@ func TestIDPTemplateProjection_reducesRemove(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_templates3 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.idp_templates4 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -198,7 +198,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_oauth2 (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.idp_templates4_oauth2 (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -269,7 +269,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_oauth2 (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.idp_templates4_oauth2 (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -317,7 +317,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_oauth2 SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_oauth2 SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -377,7 +377,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_oauth2 SET (client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) = ($1, $2, $3, $4, $5, $6, $7) WHERE (idp_id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.idp_templates4_oauth2 SET (client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) = ($1, $2, $3, $4, $5, $6, $7) WHERE (idp_id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ "client_id", anyArg{}, @@ -465,7 +465,7 @@ func TestIDPTemplateProjection_reducesAzureAD(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_azure (idp_id, instance_id, client_id, client_secret, scopes, tenant, is_email_verified) VALUES ($1, $2, $3, $4, $5, $6, $7)", + expectedStmt: "INSERT INTO projections.idp_templates4_azure (idp_id, instance_id, client_id, client_secret, scopes, tenant, is_email_verified) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -532,7 +532,7 @@ func TestIDPTemplateProjection_reducesAzureAD(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_azure (idp_id, instance_id, client_id, client_secret, scopes, tenant, is_email_verified) VALUES ($1, $2, $3, $4, $5, $6, $7)", + expectedStmt: "INSERT INTO projections.idp_templates4_azure (idp_id, instance_id, client_id, client_secret, scopes, tenant, is_email_verified) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -599,7 +599,7 @@ func TestIDPTemplateProjection_reducesAzureAD(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_azure (idp_id, instance_id, client_id, client_secret, scopes, tenant, is_email_verified) VALUES ($1, $2, $3, $4, $5, $6, $7)", + expectedStmt: "INSERT INTO projections.idp_templates4_azure (idp_id, instance_id, client_id, client_secret, scopes, tenant, is_email_verified) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -645,7 +645,7 @@ func TestIDPTemplateProjection_reducesAzureAD(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_azure SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_azure SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -703,7 +703,7 @@ func TestIDPTemplateProjection_reducesAzureAD(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_azure SET (client_id, client_secret, scopes, tenant, is_email_verified) = ($1, $2, $3, $4, $5) WHERE (idp_id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.idp_templates4_azure SET (client_id, client_secret, scopes, tenant, is_email_verified) = ($1, $2, $3, $4, $5) WHERE (idp_id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ "client_id", anyArg{}, @@ -794,7 +794,7 @@ func TestIDPTemplateProjection_reducesGitHub(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_github (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.idp_templates4_github (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -857,7 +857,7 @@ func TestIDPTemplateProjection_reducesGitHub(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_github (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.idp_templates4_github (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -901,7 +901,7 @@ func TestIDPTemplateProjection_reducesGitHub(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_github SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_github SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -957,7 +957,7 @@ func TestIDPTemplateProjection_reducesGitHub(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_github SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4_github SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "client_id", anyArg{}, @@ -1049,7 +1049,7 @@ func TestIDPTemplateProjection_reducesGitHubEnterprise(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_github_enterprise (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.idp_templates4_github_enterprise (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1118,7 +1118,7 @@ func TestIDPTemplateProjection_reducesGitHubEnterprise(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_github_enterprise (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.idp_templates4_github_enterprise (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1165,7 +1165,7 @@ func TestIDPTemplateProjection_reducesGitHubEnterprise(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_github_enterprise SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_github_enterprise SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -1224,7 +1224,7 @@ func TestIDPTemplateProjection_reducesGitHubEnterprise(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_github_enterprise SET (client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) = ($1, $2, $3, $4, $5, $6) WHERE (idp_id = $7) AND (instance_id = $8)", + expectedStmt: "UPDATE projections.idp_templates4_github_enterprise SET (client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) = ($1, $2, $3, $4, $5, $6) WHERE (idp_id = $7) AND (instance_id = $8)", expectedArgs: []interface{}{ "client_id", anyArg{}, @@ -1315,7 +1315,7 @@ func TestIDPTemplateProjection_reducesGitLab(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_gitlab (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.idp_templates4_gitlab (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1377,7 +1377,7 @@ func TestIDPTemplateProjection_reducesGitLab(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_gitlab (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.idp_templates4_gitlab (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1421,7 +1421,7 @@ func TestIDPTemplateProjection_reducesGitLab(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_gitlab SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_gitlab SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -1477,7 +1477,7 @@ func TestIDPTemplateProjection_reducesGitLab(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_gitlab SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4_gitlab SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "client_id", anyArg{}, @@ -1567,7 +1567,7 @@ func TestIDPTemplateProjection_reducesGitLabSelfHosted(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_gitlab_self_hosted (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_gitlab_self_hosted (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1632,7 +1632,7 @@ func TestIDPTemplateProjection_reducesGitLabSelfHosted(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_gitlab_self_hosted (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_gitlab_self_hosted (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1677,7 +1677,7 @@ func TestIDPTemplateProjection_reducesGitLabSelfHosted(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_gitlab_self_hosted SET issuer = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_gitlab_self_hosted SET issuer = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "issuer", "idp-id", @@ -1734,7 +1734,7 @@ func TestIDPTemplateProjection_reducesGitLabSelfHosted(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_gitlab_self_hosted SET (issuer, client_id, client_secret, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_gitlab_self_hosted SET (issuer, client_id, client_secret, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "issuer", "client_id", @@ -1823,7 +1823,7 @@ func TestIDPTemplateProjection_reducesGoogle(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.idp_templates4_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1885,7 +1885,7 @@ func TestIDPTemplateProjection_reducesGoogle(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.idp_templates4_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -1929,7 +1929,7 @@ func TestIDPTemplateProjection_reducesGoogle(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_google SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_google SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -1985,7 +1985,7 @@ func TestIDPTemplateProjection_reducesGoogle(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_google SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4_google SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "client_id", anyArg{}, @@ -2092,7 +2092,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", + expectedStmt: "INSERT INTO projections.idp_templates4_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -2191,7 +2191,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", + expectedStmt: "INSERT INTO projections.idp_templates4_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -2243,7 +2243,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "custom-zitadel-instance", anyArg{}, @@ -2253,7 +2253,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_ldap SET host = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_ldap SET host = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "host", "idp-id", @@ -2327,7 +2327,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_ldap SET (host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) WHERE (idp_id = $22) AND (instance_id = $23)", + expectedStmt: "UPDATE projections.idp_templates4_ldap SET (host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) WHERE (idp_id = $22) AND (instance_id = $23)", expectedArgs: []interface{}{ "host", "port", @@ -2375,7 +2375,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -2430,6 +2430,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { "keyId": "key-id" }, "scopes": ["profile"], + "idTokenMapping": true, "isCreationAllowed": true, "isLinkingAllowed": true, "isAutoCreation": true, @@ -2464,7 +2465,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes, id_token_mapping) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -2472,6 +2473,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { "client_id", anyArg{}, database.StringArray{"profile"}, + true, }, }, }, @@ -2494,6 +2496,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { "keyId": "key-id" }, "scopes": ["profile"], + "idTokenMapping": true, "isCreationAllowed": true, "isLinkingAllowed": true, "isAutoCreation": true, @@ -2528,7 +2531,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes, id_token_mapping) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -2536,6 +2539,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { "client_id", anyArg{}, database.StringArray{"profile"}, + true, }, }, }, @@ -2573,7 +2577,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_oidc SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_oidc SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "id", "idp-id", @@ -2601,6 +2605,7 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { "keyId": "key-id" }, "scopes": ["profile"], + "idTokenMapping": true, "isCreationAllowed": true, "isLinkingAllowed": true, "isAutoCreation": true, @@ -2630,12 +2635,13 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_oidc SET (client_id, client_secret, issuer, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_oidc SET (client_id, client_secret, issuer, scopes, id_token_mapping) = ($1, $2, $3, $4, $5) WHERE (idp_id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ "client_id", anyArg{}, "issuer", database.StringArray{"profile"}, + true, "idp-id", "instance-id", }, @@ -2782,7 +2788,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (name, is_auto_creation, change_date, sequence) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4 SET (name, is_auto_creation, change_date, sequence) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "custom-zitadel-instance", true, @@ -2818,7 +2824,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (name, is_auto_creation, change_date, sequence) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4 SET (name, is_auto_creation, change_date, sequence) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "custom-zitadel-instance", true, @@ -2861,7 +2867,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -2871,7 +2877,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes, id_token_mapping) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -2879,6 +2885,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { "client-id", anyArg{}, database.StringArray{"profile"}, + true, }, }, }, @@ -2914,7 +2921,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -2924,7 +2931,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_oidc (idp_id, instance_id, issuer, client_id, client_secret, scopes, id_token_mapping) VALUES ($1, $2, $3, $4, $5, $6, $7)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -2932,6 +2939,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { "client-id", anyArg{}, database.StringArray{"profile"}, + true, }, }, }, @@ -2967,7 +2975,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -2976,7 +2984,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_oidc SET (client_id, client_secret, issuer, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_oidc SET (client_id, client_secret, issuer, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "client-id", anyArg{}, @@ -3019,7 +3027,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -3028,7 +3036,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_oidc SET (client_id, client_secret, issuer, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_oidc SET (client_id, client_secret, issuer, scopes) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "client-id", anyArg{}, @@ -3065,7 +3073,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -3075,7 +3083,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -3113,7 +3121,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -3123,7 +3131,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -3160,7 +3168,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -3169,7 +3177,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "https://api.zitadel.ch/jwt", "https://api.zitadel.ch/keys", @@ -3206,7 +3214,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idp_templates4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -3215,7 +3223,7 @@ func TestIDPTemplateProjection_reducesOldConfig(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "https://api.zitadel.ch/jwt", "https://api.zitadel.ch/keys", @@ -3301,7 +3309,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -3361,7 +3369,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idp_templates3_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idp_templates4_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -3406,7 +3414,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_jwt SET jwt_endpoint = $1 WHERE (idp_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.idp_templates4_jwt SET jwt_endpoint = $1 WHERE (idp_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "jwt", "idp-id", @@ -3444,7 +3452,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idp_templates3 SET (is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update, change_date, sequence) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (instance_id = $8)", + expectedStmt: "UPDATE projections.idp_templates4 SET (is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update, change_date, sequence) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (instance_id = $8)", expectedArgs: []interface{}{ true, true, @@ -3457,7 +3465,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idp_templates3_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idp_templates4_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "jwt", "keys", diff --git a/internal/repository/idp/oidc.go b/internal/repository/idp/oidc.go index 630e325151..ea3b63c674 100644 --- a/internal/repository/idp/oidc.go +++ b/internal/repository/idp/oidc.go @@ -12,12 +12,13 @@ import ( type OIDCIDPAddedEvent struct { eventstore.BaseEvent `json:"-"` - ID string `json:"id"` - Name string `json:"name"` - Issuer string `json:"issuer"` - ClientID string `json:"clientId"` - ClientSecret *crypto.CryptoValue `json:"clientSecret"` - Scopes []string `json:"scopes,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Issuer string `json:"issuer"` + ClientID string `json:"clientId"` + ClientSecret *crypto.CryptoValue `json:"clientSecret"` + Scopes []string `json:"scopes,omitempty"` + IsIDTokenMapping bool `json:"idTokenMapping,omitempty"` Options } @@ -29,17 +30,19 @@ func NewOIDCIDPAddedEvent( clientID string, clientSecret *crypto.CryptoValue, scopes []string, + isIDTokenMapping bool, options Options, ) *OIDCIDPAddedEvent { return &OIDCIDPAddedEvent{ - BaseEvent: *base, - ID: id, - Name: name, - Issuer: issuer, - ClientID: clientID, - ClientSecret: clientSecret, - Scopes: scopes, - Options: options, + BaseEvent: *base, + ID: id, + Name: name, + Issuer: issuer, + ClientID: clientID, + ClientSecret: clientSecret, + Scopes: scopes, + IsIDTokenMapping: isIDTokenMapping, + Options: options, } } @@ -67,12 +70,13 @@ func OIDCIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) type OIDCIDPChangedEvent struct { eventstore.BaseEvent `json:"-"` - ID string `json:"id"` - Name *string `json:"name,omitempty"` - Issuer *string `json:"issuer,omitempty"` - ClientID *string `json:"clientId,omitempty"` - ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` - Scopes []string `json:"scopes,omitempty"` + ID string `json:"id"` + Name *string `json:"name,omitempty"` + Issuer *string `json:"issuer,omitempty"` + ClientID *string `json:"clientId,omitempty"` + ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` + Scopes []string `json:"scopes,omitempty"` + IsIDTokenMapping *bool `json:"idTokenMapping,omitempty"` OptionChanges } @@ -132,6 +136,12 @@ func ChangeOIDCScopes(scopes []string) func(*OIDCIDPChangedEvent) { } } +func ChangeOIDCIsIDTokenMapping(idTokenMapping bool) func(*OIDCIDPChangedEvent) { + return func(e *OIDCIDPChangedEvent) { + e.IsIDTokenMapping = &idTokenMapping + } +} + func (e *OIDCIDPChangedEvent) Data() interface{} { return e } diff --git a/internal/repository/instance/idp.go b/internal/repository/instance/idp.go index 44377331c4..bf34360e7b 100644 --- a/internal/repository/instance/idp.go +++ b/internal/repository/instance/idp.go @@ -130,6 +130,7 @@ func NewOIDCIDPAddedEvent( clientID string, clientSecret *crypto.CryptoValue, scopes []string, + isIDTokenMapping bool, options idp.Options, ) *OIDCIDPAddedEvent { @@ -146,6 +147,7 @@ func NewOIDCIDPAddedEvent( clientID, clientSecret, scopes, + isIDTokenMapping, options, ), } diff --git a/internal/repository/org/idp.go b/internal/repository/org/idp.go index 2ed3a68dc8..a5a0204b1a 100644 --- a/internal/repository/org/idp.go +++ b/internal/repository/org/idp.go @@ -130,6 +130,7 @@ func NewOIDCIDPAddedEvent( clientID string, clientSecret *crypto.CryptoValue, scopes []string, + isIDTokenMapping bool, options idp.Options, ) *OIDCIDPAddedEvent { @@ -146,6 +147,7 @@ func NewOIDCIDPAddedEvent( clientID, clientSecret, scopes, + isIDTokenMapping, options, ), } diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index 6d34e8b8ec..fd0cab5ee7 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -4499,6 +4499,7 @@ message AddGenericOIDCProviderRequest { string client_secret = 4 [(validate.rules).string = {min_len: 1, max_len: 200}]; repeated string scopes = 5 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}]; zitadel.idp.v1.Options provider_options = 6; + bool is_id_token_mapping = 7; } message AddGenericOIDCProviderResponse { @@ -4515,6 +4516,7 @@ message UpdateGenericOIDCProviderRequest { string client_secret = 5 [(validate.rules).string = {max_len: 200}]; repeated string scopes = 6 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}]; zitadel.idp.v1.Options provider_options = 7; + bool is_id_token_mapping = 8; } message UpdateGenericOIDCProviderResponse { diff --git a/proto/zitadel/idp.proto b/proto/zitadel/idp.proto index 4f3a583c3d..9cf248c7c2 100644 --- a/proto/zitadel/idp.proto +++ b/proto/zitadel/idp.proto @@ -288,6 +288,7 @@ message GenericOIDCConfig { string issuer = 1; string client_id = 2; repeated string scopes = 3; + bool is_id_token_mapping = 4; } message GitHubConfig { diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto index e56247ad38..788340a69f 100644 --- a/proto/zitadel/management.proto +++ b/proto/zitadel/management.proto @@ -11173,6 +11173,7 @@ message AddGenericOIDCProviderRequest { string client_secret = 4 [(validate.rules).string = {min_len: 1, max_len: 200}]; repeated string scopes = 5 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}]; zitadel.idp.v1.Options provider_options = 6; + bool is_id_token_mapping = 7; } message AddGenericOIDCProviderResponse { @@ -11189,6 +11190,7 @@ message UpdateGenericOIDCProviderRequest { string client_secret = 5 [(validate.rules).string = {max_len: 200}]; repeated string scopes = 6 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}]; zitadel.idp.v1.Options provider_options = 7; + bool is_id_token_mapping = 8; } message UpdateGenericOIDCProviderResponse {