feat: migrate external idp to other types (#5984)

* feat: migrate instance oidc to azureAD

* feat: migrate instance oidc to azureAD

* feat: migrate org oidc to azureAD

* feat: migrate oidc to google

* fix: correct idp writemodels

* fix: review changes
This commit is contained in:
Stefan Benz 2023-06-08 00:50:53 +02:00 committed by GitHub
parent 0b1738dc5d
commit 5562ee94a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1968 additions and 12 deletions

View File

@ -6,6 +6,7 @@ import (
"github.com/zitadel/zitadel/internal/api/authz"
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
object_pb "github.com/zitadel/zitadel/internal/api/grpc/object"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
)
@ -220,6 +221,22 @@ func (s *Server) UpdateGenericOIDCProvider(ctx context.Context, req *admin_pb.Up
}, nil
}
func (s *Server) MigrateGenericOIDCProvider(ctx context.Context, req *admin_pb.MigrateGenericOIDCProviderRequest) (*admin_pb.MigrateGenericOIDCProviderResponse, error) {
var details *domain.ObjectDetails
var err error
if req.GetAzure() != nil {
details, err = s.command.MigrateInstanceGenericOIDCToAzureADProvider(ctx, req.GetId(), addAzureADProviderToCommand(req.GetAzure()))
} else if req.GetGoogle() != nil {
details, err = s.command.MigrateInstanceGenericOIDCToGoogleProvider(ctx, req.GetId(), addGoogleProviderToCommand(req.GetGoogle()))
}
if err != nil {
return nil, err
}
return &admin_pb.MigrateGenericOIDCProviderResponse{
Details: object_pb.DomainToAddDetailsPb(details),
}, nil
}
func (s *Server) AddJWTProvider(ctx context.Context, req *admin_pb.AddJWTProviderRequest) (*admin_pb.AddJWTProviderResponse, error) {
id, details, err := s.command.AddInstanceJWTProvider(ctx, addJWTProviderToCommand(req))
if err != nil {

View File

@ -6,6 +6,7 @@ import (
"github.com/zitadel/zitadel/internal/api/authz"
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
object_pb "github.com/zitadel/zitadel/internal/api/grpc/object"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management"
)
@ -212,6 +213,22 @@ func (s *Server) UpdateGenericOIDCProvider(ctx context.Context, req *mgmt_pb.Upd
}, nil
}
func (s *Server) MigrateGenericOIDCProvider(ctx context.Context, req *mgmt_pb.MigrateGenericOIDCProviderRequest) (*mgmt_pb.MigrateGenericOIDCProviderResponse, error) {
var details *domain.ObjectDetails
var err error
if req.GetAzure() != nil {
details, err = s.command.MigrateOrgGenericOIDCToAzureADProvider(ctx, authz.GetCtxData(ctx).OrgID, req.GetId(), addAzureADProviderToCommand(req.GetAzure()))
} else if req.GetGoogle() != nil {
details, err = s.command.MigrateOrgGenericOIDCToGoogleProvider(ctx, authz.GetCtxData(ctx).OrgID, req.GetId(), addGoogleProviderToCommand(req.GetGoogle()))
}
if err != nil {
return nil, err
}
return &mgmt_pb.MigrateGenericOIDCProviderResponse{
Details: object_pb.DomainToAddDetailsPb(details),
}, nil
}
func (s *Server) AddJWTProvider(ctx context.Context, req *mgmt_pb.AddJWTProviderRequest) (*mgmt_pb.AddJWTProviderResponse, error) {
id, details, err := s.command.AddOrgJWTProvider(ctx, authz.GetCtxData(ctx).OrgID, addJWTProviderToCommand(req))
if err != nil {

View File

@ -211,6 +211,12 @@ func (wm *OIDCIDPWriteModel) Reduce() error {
wm.reduceAddedEvent(e)
case *idp.OIDCIDPChangedEvent:
wm.reduceChangedEvent(e)
case *idp.OIDCIDPMigratedAzureADEvent:
wm.State = domain.IDPStateMigrated
case *idp.OIDCIDPMigratedGoogleEvent:
wm.State = domain.IDPStateMigrated
case *idp.RemovedEvent:
wm.State = domain.IDPStateRemoved
case *idpconfig.IDPConfigAddedEvent:
wm.reduceIDPConfigAddedEvent(e)
case *idpconfig.IDPConfigChangedEvent:
@ -397,6 +403,8 @@ func (wm *JWTIDPWriteModel) Reduce() error {
wm.reduceAddedEvent(e)
case *idp.JWTIDPChangedEvent:
wm.reduceChangedEvent(e)
case *idp.RemovedEvent:
wm.State = domain.IDPStateRemoved
case *idpconfig.IDPConfigAddedEvent:
wm.reduceIDPConfigAddedEvent(e)
case *idpconfig.IDPConfigChangedEvent:
@ -558,6 +566,8 @@ func (wm *AzureADIDPWriteModel) Reduce() error {
switch e := event.(type) {
case *idp.AzureADIDPAddedEvent:
wm.reduceAddedEvent(e)
case *idp.OIDCIDPMigratedAzureADEvent:
wm.reduceAddedEvent(&e.AzureADIDPAddedEvent)
case *idp.AzureADIDPChangedEvent:
wm.reduceChangedEvent(e)
case *idp.RemovedEvent:
@ -1195,6 +1205,8 @@ func (wm *GoogleIDPWriteModel) Reduce() error {
wm.reduceAddedEvent(e)
case *idp.GoogleIDPChangedEvent:
wm.reduceChangedEvent(e)
case *idp.OIDCIDPMigratedGoogleEvent:
wm.reduceAddedEvent(&e.GoogleIDPAddedEvent)
case *idp.RemovedEvent:
wm.State = domain.IDPStateRemoved
}

View File

@ -97,6 +97,40 @@ func (c *Commands) UpdateInstanceGenericOIDCProvider(ctx context.Context, id str
return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) MigrateInstanceGenericOIDCToAzureADProvider(ctx context.Context, id string, provider AzureADProvider) (*domain.ObjectDetails, error) {
return c.migrateInstanceGenericOIDC(ctx, id, provider)
}
func (c *Commands) MigrateInstanceGenericOIDCToGoogleProvider(ctx context.Context, id string, provider GoogleProvider) (*domain.ObjectDetails, error) {
return c.migrateInstanceGenericOIDC(ctx, id, provider)
}
func (c *Commands) migrateInstanceGenericOIDC(ctx context.Context, id string, provider interface{}) (*domain.ObjectDetails, error) {
instanceID := authz.GetInstance(ctx).InstanceID()
instanceAgg := instance.NewAggregate(instanceID)
writeModel := NewOIDCInstanceIDPWriteModel(instanceID, id)
var validation preparation.Validation
switch p := provider.(type) {
case AzureADProvider:
validation = c.prepareMigrateInstanceOIDCToAzureADProvider(instanceAgg, writeModel, p)
case GoogleProvider:
validation = c.prepareMigrateInstanceOIDCToGoogleProvider(instanceAgg, writeModel, p)
default:
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-s9219", "Errors.IDPConfig.NotExisting")
}
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) AddInstanceJWTProvider(ctx context.Context, provider JWTProvider) (string, *domain.ObjectDetails, error) {
instanceID := authz.GetInstance(ctx).InstanceID()
instanceAgg := instance.NewAggregate(instanceID)
@ -552,7 +586,7 @@ func (c *Commands) prepareUpdateInstanceOAuthProvider(a *instance.Aggregate, wri
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-D3r1s", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-D3r1s", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -646,7 +680,7 @@ func (c *Commands) prepareUpdateInstanceOIDCProvider(a *instance.Aggregate, writ
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Dg331", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-Dg331", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -669,6 +703,91 @@ func (c *Commands) prepareUpdateInstanceOIDCProvider(a *instance.Aggregate, writ
}
}
func (c *Commands) prepareMigrateInstanceOIDCToAzureADProvider(a *instance.Aggregate, writeModel *InstanceOIDCIDPWriteModel, provider AzureADProvider) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdf3g", "Errors.Invalid.Argument")
}
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fhbr2", "Errors.Invalid.Argument")
}
if provider.ClientSecret = strings.TrimSpace(provider.ClientSecret); provider.ClientSecret == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Dzh3g", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Dg29201", "Errors.IDPConfig.NotExisting")
}
secret, err := crypto.Encrypt([]byte(provider.ClientSecret), c.idpConfigEncryption)
if err != nil {
return nil, err
}
return []eventstore.Command{
instance.NewOIDCIDPMigratedAzureADEvent(
ctx,
&a.Aggregate,
writeModel.ID,
provider.Name,
provider.ClientID,
secret,
provider.Scopes,
provider.Tenant,
provider.EmailVerified,
provider.IDPOptions,
),
}, nil
}, nil
}
}
func (c *Commands) prepareMigrateInstanceOIDCToGoogleProvider(a *instance.Aggregate, writeModel *InstanceOIDCIDPWriteModel, provider GoogleProvider) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-D3fvs", "Errors.Invalid.Argument")
}
if provider.ClientSecret = strings.TrimSpace(provider.ClientSecret); provider.ClientSecret == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-W2vqs", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Dg29202", "Errors.IDPConfig.NotExisting")
}
secret, err := crypto.Encrypt([]byte(provider.ClientSecret), c.idpConfigEncryption)
if err != nil {
return nil, err
}
return []eventstore.Command{
instance.NewOIDCIDPMigratedGoogleEvent(
ctx,
&a.Aggregate,
writeModel.ID,
provider.Name,
provider.ClientID,
secret,
provider.Scopes,
provider.IDPOptions,
),
}, nil
}, nil
}
}
func (c *Commands) prepareAddInstanceJWTProvider(a *instance.Aggregate, writeModel *InstanceJWTIDPWriteModel, provider JWTProvider) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
@ -742,7 +861,7 @@ func (c *Commands) prepareUpdateInstanceJWTProvider(a *instance.Aggregate, write
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Bhju5", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-Bhju5", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -826,7 +945,7 @@ func (c *Commands) prepareUpdateInstanceAzureADProvider(a *instance.Aggregate, w
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-BHz3q", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-BHz3q", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -904,7 +1023,7 @@ func (c *Commands) prepareUpdateInstanceGitHubProvider(a *instance.Aggregate, wr
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Dr1gs", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-Dr1gs", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -1007,7 +1126,7 @@ func (c *Commands) prepareUpdateInstanceGitHubEnterpriseProvider(a *instance.Agg
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-GBr42", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-GBr42", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -1086,7 +1205,7 @@ func (c *Commands) prepareUpdateInstanceGitLabProvider(a *instance.Aggregate, wr
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-HBReq", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-HBReq", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -1175,7 +1294,7 @@ func (c *Commands) prepareUpdateInstanceGitLabSelfHostedProvider(a *instance.Agg
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-D2tg1", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-D2tg1", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -1252,7 +1371,7 @@ func (c *Commands) prepareUpdateInstanceGoogleProvider(a *instance.Aggregate, wr
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-D3r1s", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-D3r1s", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -1371,7 +1490,7 @@ func (c *Commands) prepareUpdateInstanceLDAPProvider(a *instance.Aggregate, writ
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-ASF3F", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-ASF3F", "Errors.IDPConfig.NotExisting")
}
event, err := writeModel.NewChangedEvent(
ctx,
@ -1412,7 +1531,7 @@ func (c *Commands) prepareDeleteInstanceProvider(a *instance.Aggregate, id strin
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Se3tg", "Errors.Instance.IDPConfig.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "INST-Se3tg", "Errors.IDPConfig.NotExisting")
}
return []eventstore.Command{instance.NewIDPRemovedEvent(ctx, &a.Aggregate, id)}, nil
}, nil

View File

@ -113,6 +113,10 @@ func (wm *InstanceOIDCIDPWriteModel) AppendEvents(events ...eventstore.Event) {
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPChangedEvent)
case *instance.IDPRemovedEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.RemovedEvent)
case *instance.OIDCIDPMigratedAzureADEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedAzureADEvent)
case *instance.OIDCIDPMigratedGoogleEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedGoogleEvent)
// old events
case *instance.IDPConfigAddedEvent:
@ -141,6 +145,8 @@ func (wm *InstanceOIDCIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
instance.OIDCIDPAddedEventType,
instance.OIDCIDPChangedEventType,
instance.IDPRemovedEventType,
instance.OIDCIDPMigratedAzureADEventType,
instance.OIDCIDPMigratedGoogleEventType,
).
EventData(map[string]interface{}{"id": wm.ID}).
Or(). // old events
@ -305,6 +311,8 @@ func (wm *InstanceAzureADIDPWriteModel) AppendEvents(events ...eventstore.Event)
wm.AzureADIDPWriteModel.AppendEvents(&e.AzureADIDPAddedEvent)
case *instance.AzureADIDPChangedEvent:
wm.AzureADIDPWriteModel.AppendEvents(&e.AzureADIDPChangedEvent)
case *instance.OIDCIDPMigratedAzureADEvent:
wm.AzureADIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedAzureADEvent)
case *instance.IDPRemovedEvent:
wm.AzureADIDPWriteModel.AppendEvents(&e.RemovedEvent)
default:
@ -322,6 +330,7 @@ func (wm *InstanceAzureADIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
instance.AzureADIDPAddedEventType,
instance.AzureADIDPChangedEventType,
instance.OIDCIDPMigratedAzureADEventType,
instance.IDPRemovedEventType,
).
EventData(map[string]interface{}{"id": wm.ID}).
@ -655,6 +664,8 @@ func (wm *InstanceGoogleIDPWriteModel) AppendEvents(events ...eventstore.Event)
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPAddedEvent)
case *instance.GoogleIDPChangedEvent:
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPChangedEvent)
case *instance.OIDCIDPMigratedGoogleEvent:
wm.GoogleIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedGoogleEvent)
case *instance.IDPRemovedEvent:
wm.GoogleIDPWriteModel.AppendEvents(&e.RemovedEvent)
}
@ -670,6 +681,7 @@ func (wm *InstanceGoogleIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
instance.GoogleIDPAddedEventType,
instance.GoogleIDPChangedEventType,
instance.OIDCIDPMigratedGoogleEventType,
instance.IDPRemovedEventType,
).
EventData(map[string]interface{}{"id": wm.ID}).

View File

@ -1102,6 +1102,474 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) {
}
}
func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretCrypto crypto.EncryptionAlgorithm
}
type args struct {
ctx context.Context
id string
provider AzureADProvider
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"invalid name",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
provider: AzureADProvider{},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-sdf3g", ""))
},
},
},
{
"invalid client id",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
provider: AzureADProvider{
Name: "name",
},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Fhbr2", ""))
},
},
},
{
"invalid client secret",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Dzh3g", ""))
},
},
},
{
name: "not found",
fields: fields{
eventstore: eventstoreExpect(t,
expectFilter(),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
err: caos_errors.IsNotFound,
},
},
{
name: "migrate 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 {
event := instance.NewOIDCIDPMigratedAzureADEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
"id1",
"name",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
nil,
"",
false,
idp.Options{},
)
return event
}(),
),
},
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
},
},
{
name: "migrate ok full",
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 {
event := instance.NewOIDCIDPMigratedAzureADEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
"id1",
"name",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
[]string{"openid"},
"tenant",
true,
idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
},
)
return event
}(),
),
},
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
Scopes: []string{"openid"},
Tenant: "tenant",
EmailVerified: 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.MigrateInstanceGenericOIDCToAzureADProvider(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_MigrateInstanceOIDCToGoogleIDP(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretCrypto crypto.EncryptionAlgorithm
}
type args struct {
ctx context.Context
id string
provider GoogleProvider
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"invalid clientID",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
provider: GoogleProvider{},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-D3fvs", ""))
},
},
},
{
"invalid clientSecret",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
provider: GoogleProvider{
ClientID: "clientID",
},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-W2vqs", ""))
},
},
},
{
name: "not found",
fields: fields{
eventstore: eventstoreExpect(t,
expectFilter(),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
err: caos_errors.IsNotFound,
},
},
{
name: "migrate 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",
instance.NewOIDCIDPMigratedGoogleEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
"id1",
"",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
nil,
idp.Options{},
)),
},
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
},
},
{
name: "migrate ok full",
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",
instance.NewOIDCIDPMigratedGoogleEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
"id1",
"",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
[]string{"openid"},
idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
},
)),
},
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
ClientSecret: "clientSecret",
Scopes: []string{"openid"},
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.MigrateInstanceGenericOIDCToGoogleProvider(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

View File

@ -92,6 +92,39 @@ func (c *Commands) UpdateOrgGenericOIDCProvider(ctx context.Context, resourceOwn
return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) MigrateOrgGenericOIDCToAzureADProvider(ctx context.Context, resourceOwner, id string, provider AzureADProvider) (*domain.ObjectDetails, error) {
return c.migrateOrgGenericOIDC(ctx, resourceOwner, id, provider)
}
func (c *Commands) MigrateOrgGenericOIDCToGoogleProvider(ctx context.Context, resourceOwner, id string, provider GoogleProvider) (*domain.ObjectDetails, error) {
return c.migrateOrgGenericOIDC(ctx, resourceOwner, id, provider)
}
func (c *Commands) migrateOrgGenericOIDC(ctx context.Context, resourceOwner, id string, provider interface{}) (*domain.ObjectDetails, error) {
orgAgg := org.NewAggregate(resourceOwner)
writeModel := NewOIDCOrgIDPWriteModel(resourceOwner, id)
var validation preparation.Validation
switch p := provider.(type) {
case AzureADProvider:
validation = c.prepareMigrateOrgOIDCToAzureADProvider(orgAgg, writeModel, p)
case GoogleProvider:
validation = c.prepareMigrateOrgOIDCToGoogleProvider(orgAgg, writeModel, p)
default:
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-s9s2919", "Errors.IDPConfig.NotExisting")
}
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) AddOrgJWTProvider(ctx context.Context, resourceOwner string, provider JWTProvider) (string, *domain.ObjectDetails, error) {
orgAgg := org.NewAggregate(resourceOwner)
id, err := c.idGenerator.Next()
@ -647,6 +680,91 @@ func (c *Commands) prepareUpdateOrgOIDCProvider(a *org.Aggregate, writeModel *Or
}
}
func (c *Commands) prepareMigrateOrgOIDCToAzureADProvider(a *org.Aggregate, writeModel *OrgOIDCIDPWriteModel, provider AzureADProvider) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdf3g", "Errors.Invalid.Argument")
}
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fhbr2", "Errors.Invalid.Argument")
}
if provider.ClientSecret = strings.TrimSpace(provider.ClientSecret); provider.ClientSecret == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Dzh3g", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-Dg239201", "Errors.Instance.IDPConfig.NotExisting")
}
secret, err := crypto.Encrypt([]byte(provider.ClientSecret), c.idpConfigEncryption)
if err != nil {
return nil, err
}
return []eventstore.Command{
org.NewOIDCIDPMigratedAzureADEvent(
ctx,
&a.Aggregate,
writeModel.ID,
provider.Name,
provider.ClientID,
secret,
provider.Scopes,
provider.Tenant,
provider.EmailVerified,
provider.IDPOptions,
),
}, nil
}, nil
}
}
func (c *Commands) prepareMigrateOrgOIDCToGoogleProvider(a *org.Aggregate, writeModel *OrgOIDCIDPWriteModel, provider GoogleProvider) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-D3fvs", "Errors.Invalid.Argument")
}
if provider.ClientSecret = strings.TrimSpace(provider.ClientSecret); provider.ClientSecret == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-W2vqs", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INST-x09981", "Errors.Instance.IDPConfig.NotExisting")
}
secret, err := crypto.Encrypt([]byte(provider.ClientSecret), c.idpConfigEncryption)
if err != nil {
return nil, err
}
return []eventstore.Command{
org.NewOIDCIDPMigratedGoogleEvent(
ctx,
&a.Aggregate,
writeModel.ID,
provider.Name,
provider.ClientID,
secret,
provider.Scopes,
provider.IDPOptions,
),
}, nil
}, nil
}
}
func (c *Commands) prepareAddOrgJWTProvider(a *org.Aggregate, writeModel *OrgJWTIDPWriteModel, provider JWTProvider) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {

View File

@ -113,6 +113,10 @@ func (wm *OrgOIDCIDPWriteModel) AppendEvents(events ...eventstore.Event) {
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPAddedEvent)
case *org.OIDCIDPChangedEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPChangedEvent)
case *org.OIDCIDPMigratedAzureADEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedAzureADEvent)
case *org.OIDCIDPMigratedGoogleEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedGoogleEvent)
case *org.IDPRemovedEvent:
wm.OIDCIDPWriteModel.AppendEvents(&e.RemovedEvent)
@ -142,6 +146,8 @@ func (wm *OrgOIDCIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
org.OIDCIDPAddedEventType,
org.OIDCIDPChangedEventType,
org.OIDCIDPMigratedAzureADEventType,
org.OIDCIDPMigratedGoogleEventType,
org.IDPRemovedEventType,
).
EventData(map[string]interface{}{"id": wm.ID}).
@ -311,6 +317,8 @@ func (wm *OrgAzureADIDPWriteModel) AppendEvents(events ...eventstore.Event) {
wm.AzureADIDPWriteModel.AppendEvents(&e.AzureADIDPAddedEvent)
case *org.AzureADIDPChangedEvent:
wm.AzureADIDPWriteModel.AppendEvents(&e.AzureADIDPChangedEvent)
case *org.OIDCIDPMigratedAzureADEvent:
wm.AzureADIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedAzureADEvent)
case *org.IDPRemovedEvent:
wm.AzureADIDPWriteModel.AppendEvents(&e.RemovedEvent)
default:
@ -328,6 +336,7 @@ func (wm *OrgAzureADIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
org.AzureADIDPAddedEventType,
org.AzureADIDPChangedEventType,
org.OIDCIDPMigratedAzureADEventType,
org.IDPRemovedEventType,
).
EventData(map[string]interface{}{"id": wm.ID}).
@ -663,6 +672,8 @@ func (wm *OrgGoogleIDPWriteModel) AppendEvents(events ...eventstore.Event) {
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPAddedEvent)
case *org.GoogleIDPChangedEvent:
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPChangedEvent)
case *org.OIDCIDPMigratedGoogleEvent:
wm.GoogleIDPWriteModel.AppendEvents(&e.OIDCIDPMigratedGoogleEvent)
case *org.IDPRemovedEvent:
wm.GoogleIDPWriteModel.AppendEvents(&e.RemovedEvent)
default:
@ -680,6 +691,7 @@ func (wm *OrgGoogleIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
org.GoogleIDPAddedEventType,
org.GoogleIDPChangedEventType,
org.OIDCIDPMigratedGoogleEventType,
org.IDPRemovedEventType,
).
EventData(map[string]interface{}{"id": wm.ID}).

View File

@ -1119,6 +1119,474 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) {
}
}
func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretCrypto crypto.EncryptionAlgorithm
}
type args struct {
ctx context.Context
resourceOwner string
id string
provider AzureADProvider
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"invalid name",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
provider: AzureADProvider{},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-sdf3g", ""))
},
},
},
{
"invalid client id",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
provider: AzureADProvider{
Name: "name",
},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Fhbr2", ""))
},
},
},
{
"invalid client secret",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Dzh3g", ""))
},
},
},
{
name: "not found",
fields: fields{
eventstore: eventstoreExpect(t,
expectFilter(),
),
},
args: args{
ctx: context.Background(),
resourceOwner: "ro",
id: "id1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
err: caos_errors.IsNotFound,
},
},
{
name: "migrate 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(
[]*repository.Event{
eventFromEventPusher(
func() eventstore.Command {
event := org.NewOIDCIDPMigratedAzureADEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"id1",
"name",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
nil,
"",
false,
idp.Options{},
)
return event
}(),
),
},
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
want: &domain.ObjectDetails{ResourceOwner: "org1"},
},
},
{
name: "migrate full 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(
org.NewOIDCIDPMigratedAzureADEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"id1",
"name",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
[]string{"openid"},
"tenant",
true,
idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
},
)),
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: AzureADProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
Scopes: []string{"openid"},
Tenant: "tenant",
EmailVerified: 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.MigrateOrgGenericOIDCToAzureADProvider(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_MigrateOrgOIDCToGoogleIDP(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretCrypto crypto.EncryptionAlgorithm
}
type args struct {
ctx context.Context
resourceOwner string
id string
provider GoogleProvider
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"invalid clientID",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: GoogleProvider{},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-D3fvs", ""))
},
},
},
{
"invalid clientSecret",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
},
},
res{
err: func(err error) bool {
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-W2vqs", ""))
},
},
},
{
"not found",
fields{
eventstore: eventstoreExpect(t,
expectFilter(),
),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res{
err: caos_errors.IsNotFound,
},
},
{
name: "migrate 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(
org.NewOIDCIDPMigratedGoogleEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"id1",
"",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
nil,
idp.Options{},
)),
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
ClientSecret: "clientSecret",
},
},
res: res{
want: &domain.ObjectDetails{ResourceOwner: "org1"},
},
},
{
name: "migrate full 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(
org.NewOIDCIDPMigratedGoogleEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"id1",
"",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
[]string{"openid"},
idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
},
)),
),
),
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: GoogleProvider{
ClientID: "clientID",
ClientSecret: "clientSecret",
Scopes: []string{"openid"},
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.MigrateOrgGenericOIDCToGoogleProvider(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

View File

@ -9,6 +9,7 @@ const (
IDPStateActive
IDPStateInactive
IDPStateRemoved
IDPStateMigrated
idpStateCount
)
@ -18,7 +19,7 @@ func (s IDPState) Valid() bool {
}
func (s IDPState) Exists() bool {
return s != IDPStateUnspecified && s != IDPStateRemoved
return s != IDPStateUnspecified && s != IDPStateRemoved && s != IDPStateMigrated
}
type IDPType int32

View File

@ -347,6 +347,10 @@ func (p *idpTemplateProjection) reducers() []handler.AggregateReducer {
Event: instance.OIDCIDPChangedEventType,
Reduce: p.reduceOIDCIDPChanged,
},
{
Event: instance.OIDCIDPMigratedAzureADEventType,
Reduce: p.reduceOIDCIDPMigratedAzureAD,
},
{
Event: instance.JWTIDPAddedEventType,
Reduce: p.reduceJWTIDPAdded,
@ -755,6 +759,106 @@ func (p *idpTemplateProjection) reduceOIDCIDPChanged(event eventstore.Event) (*h
), nil
}
func (p *idpTemplateProjection) reduceOIDCIDPMigratedAzureAD(event eventstore.Event) (*handler.Statement, error) {
var idpEvent idp.OIDCIDPMigratedAzureADEvent
switch e := event.(type) {
case *org.OIDCIDPMigratedAzureADEvent:
idpEvent = e.OIDCIDPMigratedAzureADEvent
case *instance.OIDCIDPMigratedAzureADEvent:
idpEvent = e.OIDCIDPMigratedAzureADEvent
default:
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPMigratedAzureADEventType, instance.OIDCIDPMigratedAzureADEventType})
}
return crdb.NewMultiStatement(
&idpEvent,
crdb.AddUpdateStatement(
[]handler.Column{
handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeAzureAD),
handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed),
handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed),
handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation),
handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate),
},
[]handler.Condition{
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
},
),
crdb.AddDeleteStatement(
[]handler.Condition{
handler.NewCond(OIDCIDCol, idpEvent.ID),
handler.NewCond(OIDCInstanceIDCol, idpEvent.Aggregate().InstanceID),
},
crdb.WithTableSuffix(IDPTemplateOIDCSuffix),
),
crdb.AddCreateStatement(
[]handler.Column{
handler.NewCol(AzureADIDCol, idpEvent.ID),
handler.NewCol(AzureADInstanceIDCol, idpEvent.Aggregate().InstanceID),
handler.NewCol(AzureADClientIDCol, idpEvent.ClientID),
handler.NewCol(AzureADClientSecretCol, idpEvent.ClientSecret),
handler.NewCol(AzureADScopesCol, database.StringArray(idpEvent.Scopes)),
handler.NewCol(AzureADTenantCol, idpEvent.Tenant),
handler.NewCol(AzureADIsEmailVerified, idpEvent.IsEmailVerified),
},
crdb.WithTableSuffix(IDPTemplateAzureADSuffix),
),
), nil
}
func (p *idpTemplateProjection) reduceOIDCIDPMigratedGoogle(event eventstore.Event) (*handler.Statement, error) {
var idpEvent idp.OIDCIDPMigratedGoogleEvent
switch e := event.(type) {
case *org.OIDCIDPMigratedGoogleEvent:
idpEvent = e.OIDCIDPMigratedGoogleEvent
case *instance.OIDCIDPMigratedGoogleEvent:
idpEvent = e.OIDCIDPMigratedGoogleEvent
default:
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPMigratedGoogleEventType, instance.OIDCIDPMigratedGoogleEventType})
}
return crdb.NewMultiStatement(
&idpEvent,
crdb.AddUpdateStatement(
[]handler.Column{
handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeGoogle),
handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed),
handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed),
handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation),
handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate),
},
[]handler.Condition{
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
},
),
crdb.AddDeleteStatement(
[]handler.Condition{
handler.NewCond(OIDCIDCol, idpEvent.ID),
handler.NewCond(OIDCInstanceIDCol, idpEvent.Aggregate().InstanceID),
},
crdb.WithTableSuffix(IDPTemplateOIDCSuffix),
),
crdb.AddCreateStatement(
[]handler.Column{
handler.NewCol(GoogleIDCol, idpEvent.ID),
handler.NewCol(GoogleInstanceIDCol, idpEvent.Aggregate().InstanceID),
handler.NewCol(GoogleClientIDCol, idpEvent.ClientID),
handler.NewCol(GoogleClientSecretCol, idpEvent.ClientSecret),
handler.NewCol(GoogleScopesCol, database.StringArray(idpEvent.Scopes)),
},
crdb.WithTableSuffix(IDPTemplateGoogleSuffix),
),
), nil
}
func (p *idpTemplateProjection) reduceJWTIDPAdded(event eventstore.Event) (*handler.Statement, error) {
var idpEvent idp.JWTIDPAddedEvent
var idpOwnerType domain.IdentityProviderType

View File

@ -2686,6 +2686,278 @@ func TestIDPTemplateProjection_reducesOIDC(t *testing.T) {
},
},
},
{
name: "instance reduceOIDCIDPMigratedAzureAD",
args: args{
event: getEvent(testEvent(
repository.EventType(instance.OIDCIDPMigratedAzureADEventType),
instance.AggregateType,
[]byte(`{
"id": "idp-id",
"name": "name",
"client_id": "client_id",
"client_secret": {
"cryptoType": 0,
"algorithm": "RSA-265",
"keyId": "key-id"
},
"tenant": "tenant",
"isEmailVerified": true,
"scopes": ["profile"],
"isCreationAllowed": true,
"isLinkingAllowed": true,
"isAutoCreation": true,
"isAutoUpdate": true
}`),
), instance.OIDCIDPMigratedAzureADEventMapper),
},
reduce: (&idpTemplateProjection{}).reduceOIDCIDPMigratedAzureAD,
want: wantReduce{
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.idp_templates5 SET (change_date, sequence, name, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (id = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
"name",
domain.IDPTypeAzureAD,
true,
true,
true,
true,
"idp-id",
"instance-id",
},
},
{
expectedStmt: "DELETE FROM projections.idp_templates5_oidc WHERE (idp_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
},
},
{
expectedStmt: "INSERT INTO projections.idp_templates5_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",
"client_id",
anyArg{},
database.StringArray{"profile"},
"tenant",
true,
},
},
},
},
},
},
{
name: "org reduceOIDCIDPMigratedAzureAD",
args: args{
event: getEvent(testEvent(
repository.EventType(org.OIDCIDPMigratedAzureADEventType),
org.AggregateType,
[]byte(`{
"id": "idp-id",
"name": "name",
"client_id": "client_id",
"client_secret": {
"cryptoType": 0,
"algorithm": "RSA-265",
"keyId": "key-id"
},
"tenant": "tenant",
"isEmailVerified": true,
"scopes": ["profile"],
"isCreationAllowed": true,
"isLinkingAllowed": true,
"isAutoCreation": true,
"isAutoUpdate": true
}`),
), org.OIDCIDPMigratedAzureADEventMapper),
},
reduce: (&idpTemplateProjection{}).reduceOIDCIDPMigratedAzureAD,
want: wantReduce{
aggregateType: eventstore.AggregateType("org"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.idp_templates5 SET (change_date, sequence, name, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (id = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
"name",
domain.IDPTypeAzureAD,
true,
true,
true,
true,
"idp-id",
"instance-id",
},
},
{
expectedStmt: "DELETE FROM projections.idp_templates5_oidc WHERE (idp_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
},
},
{
expectedStmt: "INSERT INTO projections.idp_templates5_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",
"client_id",
anyArg{},
database.StringArray{"profile"},
"tenant",
true,
},
},
},
},
},
},
{
name: "instance reduceOIDCIDPMigratedGoogle",
args: args{
event: getEvent(testEvent(
repository.EventType(instance.OIDCIDPMigratedGoogleEventType),
instance.AggregateType,
[]byte(`{
"id": "idp-id",
"name": "name",
"clientId": "client_id",
"clientSecret": {
"cryptoType": 0,
"algorithm": "RSA-265",
"keyId": "key-id"
},
"scopes": ["profile"],
"isCreationAllowed": true,
"isLinkingAllowed": true,
"isAutoCreation": true,
"isAutoUpdate": true
}`),
), instance.OIDCIDPMigratedGoogleEventMapper),
},
reduce: (&idpTemplateProjection{}).reduceOIDCIDPMigratedGoogle,
want: wantReduce{
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.idp_templates5 SET (change_date, sequence, name, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (id = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
"name",
domain.IDPTypeGoogle,
true,
true,
true,
true,
"idp-id",
"instance-id",
},
},
{
expectedStmt: "DELETE FROM projections.idp_templates5_oidc WHERE (idp_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
},
},
{
expectedStmt: "INSERT INTO projections.idp_templates5_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
"client_id",
anyArg{},
database.StringArray{"profile"},
},
},
},
},
},
},
{
name: "org reduceOIDCIDPMigratedGoogle",
args: args{
event: getEvent(testEvent(
repository.EventType(org.OIDCIDPMigratedGoogleEventType),
org.AggregateType,
[]byte(`{
"id": "idp-id",
"name": "name",
"clientId": "client_id",
"clientSecret": {
"cryptoType": 0,
"algorithm": "RSA-265",
"keyId": "key-id"
},
"scopes": ["profile"],
"isCreationAllowed": true,
"isLinkingAllowed": true,
"isAutoCreation": true,
"isAutoUpdate": true
}`),
), org.OIDCIDPMigratedGoogleEventMapper),
},
reduce: (&idpTemplateProjection{}).reduceOIDCIDPMigratedGoogle,
want: wantReduce{
aggregateType: eventstore.AggregateType("org"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.idp_templates5 SET (change_date, sequence, name, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (id = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
"name",
domain.IDPTypeGoogle,
true,
true,
true,
true,
"idp-id",
"instance-id",
},
},
{
expectedStmt: "DELETE FROM projections.idp_templates5_oidc WHERE (idp_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
},
},
{
expectedStmt: "INSERT INTO projections.idp_templates5_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
"client_id",
anyArg{},
database.StringArray{"profile"},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -162,3 +162,93 @@ func OIDCIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error
return e, nil
}
type OIDCIDPMigratedAzureADEvent struct {
AzureADIDPAddedEvent
}
func NewOIDCIDPMigratedAzureADEvent(
base *eventstore.BaseEvent,
id,
name,
clientID string,
clientSecret *crypto.CryptoValue,
scopes []string,
tenant string,
isEmailVerified bool,
options Options,
) *OIDCIDPMigratedAzureADEvent {
return &OIDCIDPMigratedAzureADEvent{
AzureADIDPAddedEvent: AzureADIDPAddedEvent{
BaseEvent: *base,
ID: id,
Name: name,
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: scopes,
Tenant: tenant,
IsEmailVerified: isEmailVerified,
Options: options,
},
}
}
func (e *OIDCIDPMigratedAzureADEvent) Data() interface{} {
return e
}
func (e *OIDCIDPMigratedAzureADEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func OIDCIDPMigratedAzureADEventMapper(event *repository.Event) (eventstore.Event, error) {
e, err := AzureADIDPAddedEventMapper(event)
if err != nil {
return nil, err
}
return &OIDCIDPMigratedAzureADEvent{AzureADIDPAddedEvent: *e.(*AzureADIDPAddedEvent)}, nil
}
type OIDCIDPMigratedGoogleEvent struct {
GoogleIDPAddedEvent
}
func NewOIDCIDPMigratedGoogleEvent(
base *eventstore.BaseEvent,
id,
name,
clientID string,
clientSecret *crypto.CryptoValue,
scopes []string,
options Options,
) *OIDCIDPMigratedGoogleEvent {
return &OIDCIDPMigratedGoogleEvent{
GoogleIDPAddedEvent: GoogleIDPAddedEvent{
BaseEvent: *base,
ID: id,
Name: name,
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: scopes,
Options: options,
},
}
}
func (e *OIDCIDPMigratedGoogleEvent) Data() interface{} {
return e
}
func (e *OIDCIDPMigratedGoogleEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func OIDCIDPMigratedGoogleEventMapper(event *repository.Event) (eventstore.Event, error) {
e, err := GoogleIDPAddedEventMapper(event)
if err != nil {
return nil, err
}
return &OIDCIDPMigratedGoogleEvent{GoogleIDPAddedEvent: *e.(*GoogleIDPAddedEvent)}, nil
}

View File

@ -74,6 +74,8 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(AggregateType, OAuthIDPChangedEventType, OAuthIDPChangedEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPAddedEventType, OIDCIDPAddedEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPChangedEventType, OIDCIDPChangedEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPMigratedAzureADEventType, OIDCIDPMigratedAzureADEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPMigratedGoogleEventType, OIDCIDPMigratedGoogleEventMapper).
RegisterFilterEventMapper(AggregateType, JWTIDPAddedEventType, JWTIDPAddedEventMapper).
RegisterFilterEventMapper(AggregateType, JWTIDPChangedEventType, JWTIDPChangedEventMapper).
RegisterFilterEventMapper(AggregateType, AzureADIDPAddedEventType, AzureADIDPAddedEventMapper).

View File

@ -15,6 +15,8 @@ const (
OAuthIDPChangedEventType eventstore.EventType = "instance.idp.oauth.changed"
OIDCIDPAddedEventType eventstore.EventType = "instance.idp.oidc.added"
OIDCIDPChangedEventType eventstore.EventType = "instance.idp.oidc.changed"
OIDCIDPMigratedAzureADEventType eventstore.EventType = "instance.idp.oidc.migrated.azure"
OIDCIDPMigratedGoogleEventType eventstore.EventType = "instance.idp.oidc.migrated.google"
JWTIDPAddedEventType eventstore.EventType = "instance.idp.jwt.added"
JWTIDPChangedEventType eventstore.EventType = "instance.idp.jwt.changed"
AzureADIDPAddedEventType eventstore.EventType = "instance.idp.azure.added"
@ -198,6 +200,90 @@ func OIDCIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error
return &OIDCIDPChangedEvent{OIDCIDPChangedEvent: *e.(*idp.OIDCIDPChangedEvent)}, nil
}
type OIDCIDPMigratedAzureADEvent struct {
idp.OIDCIDPMigratedAzureADEvent
}
func NewOIDCIDPMigratedAzureADEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id,
name,
clientID string,
clientSecret *crypto.CryptoValue,
scopes []string,
tenant string,
isEmailVerified bool,
options idp.Options,
) *OIDCIDPMigratedAzureADEvent {
return &OIDCIDPMigratedAzureADEvent{
OIDCIDPMigratedAzureADEvent: *idp.NewOIDCIDPMigratedAzureADEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
OIDCIDPMigratedAzureADEventType,
),
id,
name,
clientID,
clientSecret,
scopes,
tenant,
isEmailVerified,
options,
),
}
}
func OIDCIDPMigratedAzureADEventMapper(event *repository.Event) (eventstore.Event, error) {
e, err := idp.OIDCIDPMigratedAzureADEventMapper(event)
if err != nil {
return nil, err
}
return &OIDCIDPMigratedAzureADEvent{OIDCIDPMigratedAzureADEvent: *e.(*idp.OIDCIDPMigratedAzureADEvent)}, nil
}
type OIDCIDPMigratedGoogleEvent struct {
idp.OIDCIDPMigratedGoogleEvent
}
func NewOIDCIDPMigratedGoogleEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id,
name,
clientID string,
clientSecret *crypto.CryptoValue,
scopes []string,
options idp.Options,
) *OIDCIDPMigratedGoogleEvent {
return &OIDCIDPMigratedGoogleEvent{
OIDCIDPMigratedGoogleEvent: *idp.NewOIDCIDPMigratedGoogleEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
OIDCIDPMigratedAzureADEventType,
),
id,
name,
clientID,
clientSecret,
scopes,
options,
),
}
}
func OIDCIDPMigratedGoogleEventMapper(event *repository.Event) (eventstore.Event, error) {
e, err := idp.OIDCIDPMigratedGoogleEventMapper(event)
if err != nil {
return nil, err
}
return &OIDCIDPMigratedGoogleEvent{OIDCIDPMigratedGoogleEvent: *e.(*idp.OIDCIDPMigratedGoogleEvent)}, nil
}
type JWTIDPAddedEvent struct {
idp.JWTIDPAddedEvent
}

View File

@ -83,6 +83,8 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(AggregateType, OAuthIDPChangedEventType, OAuthIDPChangedEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPAddedEventType, OIDCIDPAddedEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPChangedEventType, OIDCIDPChangedEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPMigratedAzureADEventType, OIDCIDPMigratedAzureADEventMapper).
RegisterFilterEventMapper(AggregateType, OIDCIDPMigratedGoogleEventType, OIDCIDPMigratedGoogleEventMapper).
RegisterFilterEventMapper(AggregateType, JWTIDPAddedEventType, JWTIDPAddedEventMapper).
RegisterFilterEventMapper(AggregateType, JWTIDPChangedEventType, JWTIDPChangedEventMapper).
RegisterFilterEventMapper(AggregateType, AzureADIDPAddedEventType, AzureADIDPAddedEventMapper).

View File

@ -15,6 +15,8 @@ const (
OAuthIDPChangedEventType eventstore.EventType = "org.idp.oauth.changed"
OIDCIDPAddedEventType eventstore.EventType = "org.idp.oidc.added"
OIDCIDPChangedEventType eventstore.EventType = "org.idp.oidc.changed"
OIDCIDPMigratedAzureADEventType eventstore.EventType = "org.idp.oidc.migrated.azure"
OIDCIDPMigratedGoogleEventType eventstore.EventType = "org.idp.oidc.migrated.google"
JWTIDPAddedEventType eventstore.EventType = "org.idp.jwt.added"
JWTIDPChangedEventType eventstore.EventType = "org.idp.jwt.changed"
AzureADIDPAddedEventType eventstore.EventType = "org.idp.azure.added"
@ -198,6 +200,90 @@ func OIDCIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error
return &OIDCIDPChangedEvent{OIDCIDPChangedEvent: *e.(*idp.OIDCIDPChangedEvent)}, nil
}
type OIDCIDPMigratedAzureADEvent struct {
idp.OIDCIDPMigratedAzureADEvent
}
func NewOIDCIDPMigratedAzureADEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id,
name,
clientID string,
clientSecret *crypto.CryptoValue,
scopes []string,
tenant string,
isEmailVerified bool,
options idp.Options,
) *OIDCIDPMigratedAzureADEvent {
return &OIDCIDPMigratedAzureADEvent{
OIDCIDPMigratedAzureADEvent: *idp.NewOIDCIDPMigratedAzureADEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
OIDCIDPMigratedAzureADEventType,
),
id,
name,
clientID,
clientSecret,
scopes,
tenant,
isEmailVerified,
options,
),
}
}
func OIDCIDPMigratedAzureADEventMapper(event *repository.Event) (eventstore.Event, error) {
e, err := idp.OIDCIDPMigratedAzureADEventMapper(event)
if err != nil {
return nil, err
}
return &OIDCIDPMigratedAzureADEvent{OIDCIDPMigratedAzureADEvent: *e.(*idp.OIDCIDPMigratedAzureADEvent)}, nil
}
type OIDCIDPMigratedGoogleEvent struct {
idp.OIDCIDPMigratedGoogleEvent
}
func NewOIDCIDPMigratedGoogleEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id,
name,
clientID string,
clientSecret *crypto.CryptoValue,
scopes []string,
options idp.Options,
) *OIDCIDPMigratedGoogleEvent {
return &OIDCIDPMigratedGoogleEvent{
OIDCIDPMigratedGoogleEvent: *idp.NewOIDCIDPMigratedGoogleEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
OIDCIDPMigratedGoogleEventType,
),
id,
name,
clientID,
clientSecret,
scopes,
options,
),
}
}
func OIDCIDPMigratedGoogleEventMapper(event *repository.Event) (eventstore.Event, error) {
e, err := idp.OIDCIDPMigratedGoogleEventMapper(event)
if err != nil {
return nil, err
}
return &OIDCIDPMigratedGoogleEvent{OIDCIDPMigratedGoogleEvent: *e.(*idp.OIDCIDPMigratedGoogleEvent)}, nil
}
type JWTIDPAddedEvent struct {
idp.JWTIDPAddedEvent
}

View File

@ -1342,6 +1342,24 @@ service AdminService {
};
}
// Migrate an existing OIDC identity provider on the instance
rpc MigrateGenericOIDCProvider(MigrateGenericOIDCProviderRequest) returns (MigrateGenericOIDCProviderResponse) {
option (google.api.http) = {
post: "/idps/generic_oidc/{id}/_migrate"
body: "*"
};
option (zitadel.v1.auth_option) = {
permission: "iam.idp.write"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "Identity Providers";
summary: "Migrate Generic OIDC Identity Provider";
description: "";
};
}
// Add a new JWT identity provider on the instance
rpc AddJWTProvider(AddJWTProviderRequest) returns (AddJWTProviderResponse) {
option (google.api.http) = {
@ -4828,6 +4846,23 @@ message UpdateGenericOIDCProviderResponse {
zitadel.v1.ObjectDetails details = 1;
}
message MigrateGenericOIDCProviderRequest{
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629023906488334\"";
}
];
oneof template {
AddAzureADProviderRequest azure = 2;
AddGoogleProviderRequest google = 3;
}
}
message MigrateGenericOIDCProviderResponse{
zitadel.v1.ObjectDetails details = 1;
}
message AddJWTProviderRequest {
string name = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},

View File

@ -6558,6 +6558,24 @@ service ManagementService {
};
}
// Migrate an existing OIDC identity provider in the organization
rpc MigrateGenericOIDCProvider(MigrateGenericOIDCProviderRequest) returns (MigrateGenericOIDCProviderResponse) {
option (google.api.http) = {
post: "/idps/generic_oidc/{id}/_migrate"
body: "*"
};
option (zitadel.v1.auth_option) = {
permission: "org.idp.write"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "Identity Providers";
summary: "Migrate Generic OIDC Identity Provider";
description: "";
};
}
// Add a new JWT identity provider in the organization
rpc AddJWTProvider(AddJWTProviderRequest) returns (AddJWTProviderResponse) {
option (google.api.http) = {
@ -11526,6 +11544,23 @@ message UpdateGenericOIDCProviderResponse {
zitadel.v1.ObjectDetails details = 1;
}
message MigrateGenericOIDCProviderRequest{
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629023906488334\"";
}
];
oneof template {
AddAzureADProviderRequest azure = 2;
AddGoogleProviderRequest google = 3;
}
}
message MigrateGenericOIDCProviderResponse{
zitadel.v1.ObjectDetails details = 1;
}
message AddJWTProviderRequest {
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
string issuer = 2 [