fix(projections): user idp link projection (#2583)

* fix(projections): add app

* fix(migration): add index for project_id

* test: app projection

* fix(projections): add idp_user_link

* test: idp user link

* fix: migration versions

* refactor: rename externalIDP to UserIDPLink

* fix: interface methods
This commit is contained in:
Silvan
2021-11-02 10:08:47 +01:00
committed by GitHub
parent 5ba1e45423
commit 92f9eedbe0
38 changed files with 626 additions and 359 deletions

View File

@@ -145,7 +145,7 @@ func (c *Commands) ReactivateDefaultIDPConfig(ctx context.Context, idpID string)
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
}
func (c *Commands) RemoveDefaultIDPConfig(ctx context.Context, idpID string, idpProviders []*domain.IDPProvider, externalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveDefaultIDPConfig(ctx context.Context, idpID string, idpProviders []*domain.IDPProvider, externalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
existingIDP, err := c.iamIDPConfigWriteModelByID(ctx, idpID)
if err != nil {
return nil, err

View File

@@ -123,7 +123,7 @@ func (c *Commands) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, idpPr
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
}
func (c *Commands) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
if !idpProvider.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-66m9s", "Errors.IAM.LoginPolicy.IDP.Invalid")
}
@@ -158,7 +158,7 @@ func (c *Commands) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context,
return writeModelToObjectDetails(&idpModel.IdentityProviderWriteModel.WriteModel), nil
}
func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, idpProvider *domain.IDPProvider, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.EventPusher {
func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, idpProvider *domain.IDPProvider, cascade bool, cascadeExternalIDPs ...*domain.UserIDPLink) []eventstore.EventPusher {
var events []eventstore.EventPusher
if cascade {
events = append(events, iam_repo.NewIdentityProviderCascadeRemovedEvent(ctx, iamAgg, idpProvider.IDPConfigID))
@@ -167,7 +167,7 @@ func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context,
}
for _, idp := range cascadeExternalIDPs {
userEvent, _, err := c.removeHumanExternalIDP(ctx, idp, true)
userEvent, _, err := c.removeUserIDPLink(ctx, idp, true)
if err != nil {
logging.LogWithFields("COMMAND-4nfsf", "userid", idp.AggregateID, "idp-id", idp.IDPConfigID).WithError(err).Warn("could not cascade remove externalidp in remove provider from policy")
continue

View File

@@ -497,7 +497,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
type args struct {
ctx context.Context
provider *domain.IDPProvider
cascadeExternalIDPs []*domain.ExternalIDP
cascadeExternalIDPs []*domain.UserIDPLink
}
type res struct {
want *domain.ObjectDetails
@@ -708,7 +708,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
provider: &domain.IDPProvider{
IDPConfigID: "config1",
},
cascadeExternalIDPs: []*domain.ExternalIDP{
cascadeExternalIDPs: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
@@ -751,7 +751,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
),
expectFilter(
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1", "", "externaluser1"),
),
@@ -764,11 +764,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
"config1"),
),
eventFromEventPusher(
user.NewHumanExternalIDPCascadeRemovedEvent(context.Background(),
user.NewUserIDPLinkCascadeRemovedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1", "externaluser1")),
},
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("config1", "externaluser1")),
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "externaluser1")),
),
),
},
@@ -777,7 +777,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
provider: &domain.IDPProvider{
IDPConfigID: "config1",
},
cascadeExternalIDPs: []*domain.ExternalIDP{
cascadeExternalIDPs: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",

View File

@@ -153,7 +153,7 @@ func (c *Commands) ReactivateIDPConfig(ctx context.Context, idpID, orgID string)
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
}
func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
existingIDP, err := c.orgIDPConfigWriteModelByID(ctx, idpID, orgID)
if err != nil {
return nil, err
@@ -173,7 +173,7 @@ func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cas
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
}
func (c *Commands) removeIDPConfig(ctx context.Context, existingIDP *OrgIDPConfigWriteModel, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.ExternalIDP) ([]eventstore.EventPusher, error) {
func (c *Commands) removeIDPConfig(ctx context.Context, existingIDP *OrgIDPConfigWriteModel, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.UserIDPLink) ([]eventstore.EventPusher, error) {
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
return nil, caos_errs.ThrowNotFound(nil, "Org-Yx9vd", "Errors.Org.IDPConfig.NotExisting")
}

View File

@@ -426,7 +426,7 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
idpID string
orgID string
cascadeRemoveProvider bool
cascadeExternalIDPs []*domain.ExternalIDP
cascadeExternalIDPs []*domain.UserIDPLink
}
type res struct {
want *domain.ObjectDetails
@@ -531,7 +531,7 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
),
),
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&org.NewAggregate("user1", "org1").Aggregate,
"idp1",
"name",
@@ -550,14 +550,14 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"idp1",
),
user.NewHumanExternalIDPCascadeRemovedEvent(context.Background(),
user.NewUserIDPLinkCascadeRemovedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"idp1",
"id1",
),
),
uniqueConstraintsFromEventConstraint(idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name1", "org1")),
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("idp1", "id1")),
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("idp1", "id1")),
),
),
},
@@ -566,7 +566,7 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
"idp1",
"org1",
true,
[]*domain.ExternalIDP{
[]*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",

View File

@@ -201,7 +201,7 @@ func (c *Commands) AddIDPProviderToLoginPolicy(ctx context.Context, resourceOwne
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
}
func (c *Commands) RemoveIDPProviderFromLoginPolicy(ctx context.Context, resourceOwner string, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveIDPProviderFromLoginPolicy(ctx context.Context, resourceOwner string, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
if resourceOwner == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-M0fs9", "Errors.ResourceOwnerMissing")
}
@@ -239,7 +239,7 @@ func (c *Commands) RemoveIDPProviderFromLoginPolicy(ctx context.Context, resourc
return writeModelToObjectDetails(&idpModel.WriteModel), nil
}
func (c *Commands) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg *eventstore.Aggregate, idpConfigID string, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.EventPusher {
func (c *Commands) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg *eventstore.Aggregate, idpConfigID string, cascade bool, cascadeExternalIDPs ...*domain.UserIDPLink) []eventstore.EventPusher {
var events []eventstore.EventPusher
if cascade {
events = append(events, org.NewIdentityProviderCascadeRemovedEvent(ctx, orgAgg, idpConfigID))
@@ -248,7 +248,7 @@ func (c *Commands) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg
}
for _, idp := range cascadeExternalIDPs {
event, _, err := c.removeHumanExternalIDP(ctx, idp, true)
event, _, err := c.removeUserIDPLink(ctx, idp, true)
if err != nil {
logging.LogWithFields("COMMAND-n8RRf", "userid", idp.AggregateID, "idpconfigid", idp.IDPConfigID).WithError(err).Warn("could not cascade remove external idp")
continue

View File

@@ -824,7 +824,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
ctx context.Context
resourceOwner string
provider *domain.IDPProvider
cascadeExternalIDPs []*domain.ExternalIDP
cascadeExternalIDPs []*domain.UserIDPLink
}
type res struct {
want *domain.ObjectDetails
@@ -1069,7 +1069,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
Name: "name",
Type: domain.IdentityProviderTypeOrg,
},
cascadeExternalIDPs: []*domain.ExternalIDP{
cascadeExternalIDPs: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
@@ -1113,7 +1113,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
),
expectFilter(
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1", "", "externaluser1"),
),
@@ -1126,11 +1126,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
"config1"),
),
eventFromEventPusher(
user.NewHumanExternalIDPCascadeRemovedEvent(context.Background(),
user.NewUserIDPLinkCascadeRemovedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1", "externaluser1")),
},
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("config1", "externaluser1")),
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "externaluser1")),
),
),
},
@@ -1140,7 +1140,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
provider: &domain.IDPProvider{
IDPConfigID: "config1",
},
cascadeExternalIDPs: []*domain.ExternalIDP{
cascadeExternalIDPs: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",

View File

@@ -131,7 +131,7 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.UserRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.UniqueUsername)
rm.listRemoveUniqueConstraint(e.Aggregate().ID, user.UniqueExternalIDPType)
rm.listRemoveUniqueConstraint(e.Aggregate().ID, user.UniqueUserIDPLinkType)
case *user.UsernameChangedEvent:
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
if err != nil {
@@ -146,12 +146,12 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
continue
}
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.HumanExternalIDPAddedEvent:
rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
case *user.HumanExternalIDPRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
case *user.HumanExternalIDPCascadeRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
case *user.UserIDPLinkAddedEvent:
rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
case *user.UserIDPLinkRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType)
case *user.UserIDPLinkCascadeRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType)
case *usergrant.UserGrantAddedEvent:
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.NewAddUserGrantUniqueConstraint(e.Aggregate().ResourceOwner, e.UserID, e.ProjectID, e.ProjectGrantID))
case *usergrant.UserGrantRemovedEvent:
@@ -224,9 +224,9 @@ func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder {
user.UserUserNameChangedType,
user.UserDomainClaimedType,
user.UserRemovedType,
user.HumanExternalIDPAddedType,
user.HumanExternalIDPRemovedType,
user.HumanExternalIDPCascadeRemovedType,
user.UserIDPLinkAddedType,
user.UserIDPLinkRemovedType,
user.UserIDPLinkCascadeRemovedType,
usergrant.UserGrantAddedType,
usergrant.UserGrantRemovedType,
usergrant.UserGrantCascadeRemovedType,

View File

@@ -188,7 +188,7 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
}
var events []eventstore.EventPusher
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, existingUser.ExternalIDPs, orgIAMPolicy.UserLoginMustBeDomain))
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, existingUser.IDPLinks, orgIAMPolicy.UserLoginMustBeDomain))
for _, grantID := range cascadingGrantIDs {
removeEvent, _, err := c.removeUserGrant(ctx, grantID, "", true)

View File

@@ -117,7 +117,7 @@ func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
}
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string) (*domain.Human, error) {
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgMemberRoles []string) (*domain.Human, error) {
if orgID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
}
@@ -129,7 +129,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound")
}
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, externalIDP, orgIAMPolicy, pwPolicy)
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, orgIAMPolicy, pwPolicy)
if err != nil {
return nil, err
}
@@ -163,20 +163,20 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
return writeModelToHuman(registeredHuman), nil
}
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
if human != nil && human.Username == "" {
human.Username = human.EmailAddress
}
if orgID == "" || !human.IsValid() || externalIDP == nil && (human.Password == nil || human.SecretString == "") {
if orgID == "" || !human.IsValid() || link == nil && (human.Password == nil || human.SecretString == "") {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-9dk45", "Errors.User.Invalid")
}
if human.Password != nil && human.SecretString != "" {
human.ChangeRequired = false
}
return c.createHuman(ctx, orgID, human, externalIDP, true, false, orgIAMPolicy, pwPolicy)
return c.createHuman(ctx, orgID, human, link, true, false, orgIAMPolicy, pwPolicy)
}
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, selfregister, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
if err := human.CheckOrgIAMPolicy(orgIAMPolicy); err != nil {
return nil, nil, err
}
@@ -216,15 +216,15 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
events = append(events, createAddHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
}
if externalIDP != nil {
event, err := c.addHumanExternalIDP(ctx, userAgg, externalIDP)
if link != nil {
event, err := c.addUserIDPLink(ctx, userAgg, link)
if err != nil {
return nil, nil, err
}
events = append(events, event)
}
if human.IsInitialState(passwordless, externalIDP != nil) {
if human.IsInitialState(passwordless, link != nil) {
initCode, err := domain.NewInitUserCode(c.initializeUserCode)
if err != nil {
return nil, nil, err

View File

@@ -1,116 +0,0 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/repository/user"
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) BulkAddedHumanExternalIDP(ctx context.Context, userID, resourceOwner string, externalIDPs []*domain.ExternalIDP) (err error) {
if userID == "" {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-03j8f", "Errors.IDMissing")
}
if len(externalIDPs) == 0 {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-Ek9s", "Errors.User.ExternalIDP.MinimumExternalIDPNeeded")
}
events := make([]eventstore.EventPusher, len(externalIDPs))
for i, externalIDP := range externalIDPs {
externalIDPWriteModel := NewHumanExternalIDPWriteModel(userID, externalIDP.IDPConfigID, externalIDP.ExternalUserID, resourceOwner)
userAgg := UserAggregateFromWriteModel(&externalIDPWriteModel.WriteModel)
events[i], err = c.addHumanExternalIDP(ctx, userAgg, externalIDP)
if err != nil {
return err
}
}
_, err = c.eventstore.PushEvents(ctx, events...)
return err
}
func (c *Commands) addHumanExternalIDP(ctx context.Context, humanAgg *eventstore.Aggregate, externalIDP *domain.ExternalIDP) (eventstore.EventPusher, error) {
if externalIDP.AggregateID != "" && humanAgg.ID != externalIDP.AggregateID {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-33M0g", "Errors.IDMissing")
}
if !externalIDP.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6m9Kd", "Errors.User.ExternalIDP.Invalid")
}
_, err := c.getOrgIDPConfigByID(ctx, externalIDP.IDPConfigID, humanAgg.ResourceOwner)
if caos_errs.IsNotFound(err) {
_, err = c.getIAMIDPConfigByID(ctx, externalIDP.IDPConfigID)
}
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-39nfs", "Errors.IDPConfig.NotExisting")
}
return user.NewHumanExternalIDPAddedEvent(ctx, humanAgg, externalIDP.IDPConfigID, externalIDP.DisplayName, externalIDP.ExternalUserID), nil
}
func (c *Commands) RemoveHumanExternalIDP(ctx context.Context, externalIDP *domain.ExternalIDP) (*domain.ObjectDetails, error) {
event, externalIDPWriteModel, err := c.removeHumanExternalIDP(ctx, externalIDP, false)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(externalIDPWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&externalIDPWriteModel.WriteModel), nil
}
func (c *Commands) removeHumanExternalIDP(ctx context.Context, externalIDP *domain.ExternalIDP, cascade bool) (eventstore.EventPusher, *HumanExternalIDPWriteModel, error) {
if !externalIDP.IsValid() || externalIDP.AggregateID == "" {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M9ds", "Errors.IDMissing")
}
existingExternalIDP, err := c.externalIDPWriteModelByID(ctx, externalIDP.AggregateID, externalIDP.IDPConfigID, externalIDP.ExternalUserID, externalIDP.ResourceOwner)
if err != nil {
return nil, nil, err
}
if existingExternalIDP.State == domain.ExternalIDPStateUnspecified || existingExternalIDP.State == domain.ExternalIDPStateRemoved {
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-1M9xR", "Errors.User.ExternalIDP.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingExternalIDP.WriteModel)
if cascade {
return user.NewHumanExternalIDPCascadeRemovedEvent(ctx, userAgg, externalIDP.IDPConfigID, externalIDP.ExternalUserID), existingExternalIDP, nil
}
return user.NewHumanExternalIDPRemovedEvent(ctx, userAgg, externalIDP.IDPConfigID, externalIDP.ExternalUserID), existingExternalIDP, nil
}
func (c *Commands) HumanExternalLoginChecked(ctx context.Context, orgID, userID string, authRequest *domain.AuthRequest) (err error) {
if userID == "" {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5n8sM", "Errors.IDMissing")
}
existingHuman, err := c.getHumanWriteModelByID(ctx, userID, orgID)
if err != nil {
return err
}
if existingHuman.UserState == domain.UserStateUnspecified || existingHuman.UserState == domain.UserStateDeleted {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dn88J", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingHuman.WriteModel)
_, err = c.eventstore.PushEvents(ctx, user.NewHumanExternalIDPCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)))
return err
}
func (c *Commands) externalIDPWriteModelByID(ctx context.Context, userID, idpConfigID, externalUserID, resourceOwner string) (writeModel *HumanExternalIDPWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resourceOwner)
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1425,7 +1425,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
ctx context.Context
orgID string
human *domain.Human
externalIDP *domain.ExternalIDP
link *domain.UserIDPLink
orgMemberRoles []string
}
type res struct {
@@ -2134,7 +2134,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
phoneVerificationCode: tt.fields.secretGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
}
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.externalIDP, tt.args.orgMemberRoles)
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -0,0 +1,117 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/repository/user"
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) BulkAddedUserIDPLinks(ctx context.Context, userID, resourceOwner string, links []*domain.UserIDPLink) (err error) {
if userID == "" {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-03j8f", "Errors.IDMissing")
}
if len(links) == 0 {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-Ek9s", "Errors.User.ExternalIDP.MinimumExternalIDPNeeded")
}
events := make([]eventstore.EventPusher, len(links))
for i, link := range links {
linkWriteModel := NewUserIDPLinkWriteModel(userID, link.IDPConfigID, link.ExternalUserID, resourceOwner)
userAgg := UserAggregateFromWriteModel(&linkWriteModel.WriteModel)
events[i], err = c.addUserIDPLink(ctx, userAgg, link)
if err != nil {
return err
}
}
_, err = c.eventstore.PushEvents(ctx, events...)
return err
}
func (c *Commands) addUserIDPLink(ctx context.Context, human *eventstore.Aggregate, link *domain.UserIDPLink) (eventstore.EventPusher, error) {
if link.AggregateID != "" && human.ID != link.AggregateID {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-33M0g", "Errors.IDMissing")
}
if !link.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6m9Kd", "Errors.User.ExternalIDP.Invalid")
}
_, err := c.getOrgIDPConfigByID(ctx, link.IDPConfigID, human.ResourceOwner)
if caos_errs.IsNotFound(err) {
_, err = c.getIAMIDPConfigByID(ctx, link.IDPConfigID)
}
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-39nfs", "Errors.IDPConfig.NotExisting")
}
return user.NewUserIDPLinkAddedEvent(ctx, human, link.IDPConfigID, link.DisplayName, link.ExternalUserID), nil
}
func (c *Commands) RemoveUserIDPLink(ctx context.Context, link *domain.UserIDPLink) (*domain.ObjectDetails, error) {
event, linkWriteModel, err := c.removeUserIDPLink(ctx, link, false)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(linkWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&linkWriteModel.WriteModel), nil
}
func (c *Commands) removeUserIDPLink(ctx context.Context, link *domain.UserIDPLink, cascade bool) (eventstore.EventPusher, *UserIDPLinkWriteModel, error) {
if !link.IsValid() || link.AggregateID == "" {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M9ds", "Errors.IDMissing")
}
existingLink, err := c.userIDPLinkWriteModelByID(ctx, link.AggregateID, link.IDPConfigID, link.ExternalUserID, link.ResourceOwner)
if err != nil {
return nil, nil, err
}
if existingLink.State == domain.UserIDPLinkStateUnspecified || existingLink.State == domain.UserIDPLinkStateRemoved {
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-1M9xR", "Errors.User.ExternalIDP.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingLink.WriteModel)
if cascade {
return user.NewUserIDPLinkCascadeRemovedEvent(ctx, userAgg, link.IDPConfigID, link.ExternalUserID), existingLink, nil
}
return user.NewUserIDPLinkRemovedEvent(ctx, userAgg, link.IDPConfigID, link.ExternalUserID), existingLink, nil
}
func (c *Commands) UserIDPLoginChecked(ctx context.Context, orgID, userID string, authRequest *domain.AuthRequest) (err error) {
if userID == "" {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5n8sM", "Errors.IDMissing")
}
existingHuman, err := c.getHumanWriteModelByID(ctx, userID, orgID)
if err != nil {
return err
}
if existingHuman.UserState == domain.UserStateUnspecified || existingHuman.UserState == domain.UserStateDeleted {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dn88J", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingHuman.WriteModel)
_, err = c.eventstore.PushEvents(ctx, user.NewUserIDPCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)))
return err
}
func (c *Commands) userIDPLinkWriteModelByID(ctx context.Context, userID, idpConfigID, externalUserID, resourceOwner string) (writeModel *UserIDPLinkWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewUserIDPLinkWriteModel(userID, idpConfigID, externalUserID, resourceOwner)
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -6,18 +6,18 @@ import (
"github.com/caos/zitadel/internal/repository/user"
)
type HumanExternalIDPWriteModel struct {
type UserIDPLinkWriteModel struct {
eventstore.WriteModel
IDPConfigID string
ExternalUserID string
DisplayName string
State domain.ExternalIDPState
State domain.UserIDPLinkState
}
func NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resourceOwner string) *HumanExternalIDPWriteModel {
return &HumanExternalIDPWriteModel{
func NewUserIDPLinkWriteModel(userID, idpConfigID, externalUserID, resourceOwner string) *UserIDPLinkWriteModel {
return &UserIDPLinkWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
ResourceOwner: resourceOwner,
@@ -27,20 +27,20 @@ func NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resource
}
}
func (wm *HumanExternalIDPWriteModel) AppendEvents(events ...eventstore.EventReader) {
func (wm *UserIDPLinkWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanExternalIDPAddedEvent:
case *user.UserIDPLinkAddedEvent:
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
continue
}
wm.WriteModel.AppendEvents(e)
case *user.HumanExternalIDPRemovedEvent:
case *user.UserIDPLinkRemovedEvent:
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
continue
}
wm.WriteModel.AppendEvents(e)
case *user.HumanExternalIDPCascadeRemovedEvent:
case *user.UserIDPLinkCascadeRemovedEvent:
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
continue
}
@@ -51,34 +51,34 @@ func (wm *HumanExternalIDPWriteModel) AppendEvents(events ...eventstore.EventRea
}
}
func (wm *HumanExternalIDPWriteModel) Reduce() error {
func (wm *UserIDPLinkWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanExternalIDPAddedEvent:
case *user.UserIDPLinkAddedEvent:
wm.IDPConfigID = e.IDPConfigID
wm.DisplayName = e.DisplayName
wm.ExternalUserID = e.ExternalUserID
wm.State = domain.ExternalIDPStateActive
case *user.HumanExternalIDPRemovedEvent:
wm.State = domain.ExternalIDPStateRemoved
case *user.HumanExternalIDPCascadeRemovedEvent:
wm.State = domain.ExternalIDPStateRemoved
wm.State = domain.UserIDPLinkStateActive
case *user.UserIDPLinkRemovedEvent:
wm.State = domain.UserIDPLinkStateRemoved
case *user.UserIDPLinkCascadeRemovedEvent:
wm.State = domain.UserIDPLinkStateRemoved
case *user.UserRemovedEvent:
wm.State = domain.ExternalIDPStateRemoved
wm.State = domain.UserIDPLinkStateRemoved
}
}
return wm.WriteModel.Reduce()
}
func (wm *HumanExternalIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
func (wm *UserIDPLinkWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(user.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(user.HumanExternalIDPAddedType,
user.HumanExternalIDPRemovedType,
user.HumanExternalIDPCascadeRemovedType,
EventTypes(user.UserIDPLinkAddedType,
user.UserIDPLinkRemovedType,
user.UserIDPLinkCascadeRemovedType,
user.UserRemovedType).
Builder()
}

View File

@@ -17,7 +17,7 @@ import (
"github.com/caos/zitadel/internal/repository/user"
)
func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
func TestCommandSide_BulkAddUserIDPLinks(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
@@ -25,7 +25,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
ctx context.Context
userID string
resourceOwner string
externalIDPs []*domain.ExternalIDP
links []*domain.UserIDPLink
}
type res struct {
err func(error) bool
@@ -46,7 +46,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
args: args{
ctx: context.Background(),
userID: "",
externalIDPs: []*domain.ExternalIDP{
links: []*domain.UserIDPLink{
{
IDPConfigID: "config1",
ExternalUserID: "externaluser1",
@@ -85,7 +85,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
externalIDPs: []*domain.ExternalIDP{
links: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user2",
@@ -110,7 +110,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
externalIDPs: []*domain.ExternalIDP{
links: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
@@ -137,7 +137,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
externalIDPs: []*domain.ExternalIDP{
links: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
@@ -171,7 +171,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
expectPush(
[]*repository.Event{
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1",
"name",
@@ -179,7 +179,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
),
),
},
uniqueConstraintsFromEventConstraint(user.NewAddExternalIDPUniqueConstraint("config1", "externaluser1")),
uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("config1", "externaluser1")),
),
),
},
@@ -187,7 +187,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
externalIDPs: []*domain.ExternalIDP{
links: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
@@ -221,7 +221,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
expectPush(
[]*repository.Event{
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1",
"name",
@@ -229,7 +229,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
),
),
},
uniqueConstraintsFromEventConstraint(user.NewAddExternalIDPUniqueConstraint("config1", "externaluser1")),
uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("config1", "externaluser1")),
),
),
},
@@ -237,7 +237,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
externalIDPs: []*domain.ExternalIDP{
links: []*domain.UserIDPLink{
{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
@@ -256,7 +256,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
err := r.BulkAddedHumanExternalIDP(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.externalIDPs)
err := r.BulkAddedUserIDPLinks(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.links)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -267,13 +267,13 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
}
}
func TestCommandSide_RemoveExternalIDP(t *testing.T) {
func TestCommandSide_RemoveUserIDPLink(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
externalIDP *domain.ExternalIDP
ctx context.Context
link *domain.UserIDPLink
}
type res struct {
want *domain.ObjectDetails
@@ -294,7 +294,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
},
args: args{
ctx: context.Background(),
externalIDP: &domain.ExternalIDP{
link: &domain.UserIDPLink{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
},
@@ -315,7 +315,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
},
args: args{
ctx: context.Background(),
externalIDP: &domain.ExternalIDP{
link: &domain.UserIDPLink{
IDPConfigID: "config1",
ExternalUserID: "externaluser1",
},
@@ -331,7 +331,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
t,
expectFilter(
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1",
"name",
@@ -351,7 +351,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
},
args: args{
ctx: context.Background(),
externalIDP: &domain.ExternalIDP{
link: &domain.UserIDPLink{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
},
@@ -373,7 +373,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
},
args: args{
ctx: context.Background(),
externalIDP: &domain.ExternalIDP{
link: &domain.UserIDPLink{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
},
@@ -392,7 +392,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
t,
expectFilter(
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1",
"name",
@@ -403,20 +403,20 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
expectPush(
[]*repository.Event{
eventFromEventPusher(
user.NewHumanExternalIDPRemovedEvent(context.Background(),
user.NewUserIDPLinkRemovedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1",
"externaluser1",
),
),
},
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("config1", "externaluser1")),
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "externaluser1")),
),
),
},
args: args{
ctx: context.Background(),
externalIDP: &domain.ExternalIDP{
link: &domain.UserIDPLink{
ObjectRoot: models.ObjectRoot{
AggregateID: "user1",
},
@@ -436,7 +436,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.RemoveHumanExternalIDP(tt.args.ctx, tt.args.externalIDP)
got, err := r.RemoveUserIDPLink(tt.args.ctx, tt.args.link)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -492,7 +492,7 @@ func TestCommandSide_ExternalLoginCheck(t *testing.T) {
t,
expectFilter(
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"config1",
"name",
@@ -543,7 +543,7 @@ func TestCommandSide_ExternalLoginCheck(t *testing.T) {
expectPush(
[]*repository.Event{
eventFromEventPusher(
user.NewHumanExternalIDPCheckSucceededEvent(context.Background(),
user.NewUserIDPCheckSucceededEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
&user.AuthRequestInfo{
ID: "request1",
@@ -574,7 +574,7 @@ func TestCommandSide_ExternalLoginCheck(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
err := r.HumanExternalLoginChecked(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.authRequest)
err := r.UserIDPLoginChecked(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.authRequest)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -13,9 +13,9 @@ import (
type UserWriteModel struct {
eventstore.WriteModel
UserName string
ExternalIDPs []*domain.ExternalIDP
UserState domain.UserState
UserName string
IDPLinks []*domain.UserIDPLink
UserState domain.UserState
}
func NewUserWriteModel(userID, resourceOwner string) *UserWriteModel {
@@ -24,7 +24,7 @@ func NewUserWriteModel(userID, resourceOwner string) *UserWriteModel {
AggregateID: userID,
ResourceOwner: resourceOwner,
},
ExternalIDPs: make([]*domain.ExternalIDP, 0),
IDPLinks: make([]*domain.UserIDPLink, 0),
}
}
@@ -41,24 +41,24 @@ func (wm *UserWriteModel) Reduce() error {
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.UserState = domain.UserStateActive
case *user.HumanExternalIDPAddedEvent:
wm.ExternalIDPs = append(wm.ExternalIDPs, &domain.ExternalIDP{IDPConfigID: e.IDPConfigID, ExternalUserID: e.ExternalUserID})
case *user.HumanExternalIDPRemovedEvent:
idx, _ := wm.ExternalIDPByID(e.IDPConfigID, e.ExternalUserID)
case *user.UserIDPLinkAddedEvent:
wm.IDPLinks = append(wm.IDPLinks, &domain.UserIDPLink{IDPConfigID: e.IDPConfigID, ExternalUserID: e.ExternalUserID})
case *user.UserIDPLinkRemovedEvent:
idx, _ := wm.IDPLinkByID(e.IDPConfigID, e.ExternalUserID)
if idx < 0 {
continue
}
copy(wm.ExternalIDPs[idx:], wm.ExternalIDPs[idx+1:])
wm.ExternalIDPs[len(wm.ExternalIDPs)-1] = nil
wm.ExternalIDPs = wm.ExternalIDPs[:len(wm.ExternalIDPs)-1]
case *user.HumanExternalIDPCascadeRemovedEvent:
idx, _ := wm.ExternalIDPByID(e.IDPConfigID, e.ExternalUserID)
copy(wm.IDPLinks[idx:], wm.IDPLinks[idx+1:])
wm.IDPLinks[len(wm.IDPLinks)-1] = nil
wm.IDPLinks = wm.IDPLinks[:len(wm.IDPLinks)-1]
case *user.UserIDPLinkCascadeRemovedEvent:
idx, _ := wm.IDPLinkByID(e.IDPConfigID, e.ExternalUserID)
if idx < 0 {
continue
}
copy(wm.ExternalIDPs[idx:], wm.ExternalIDPs[idx+1:])
wm.ExternalIDPs[len(wm.ExternalIDPs)-1] = nil
wm.ExternalIDPs = wm.ExternalIDPs[:len(wm.ExternalIDPs)-1]
copy(wm.IDPLinks[idx:], wm.IDPLinks[idx+1:])
wm.IDPLinks[len(wm.IDPLinks)-1] = nil
wm.IDPLinks = wm.IDPLinks[:len(wm.IDPLinks)-1]
case *user.MachineAddedEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateActive
@@ -96,9 +96,9 @@ func (wm *UserWriteModel) Query() *eventstore.SearchQueryBuilder {
user.HumanAddedType,
user.HumanRegisteredType,
user.HumanInitializedCheckSucceededType,
user.HumanExternalIDPAddedType,
user.HumanExternalIDPRemovedType,
user.HumanExternalIDPCascadeRemovedType,
user.UserIDPLinkAddedType,
user.UserIDPLinkRemovedType,
user.UserIDPLinkCascadeRemovedType,
user.MachineAddedEventType,
user.UserUserNameChangedType,
user.MachineChangedEventType,
@@ -149,8 +149,8 @@ func hasUserState(check domain.UserState, states ...domain.UserState) bool {
return false
}
func (wm *UserWriteModel) ExternalIDPByID(idpID, externalUserID string) (idx int, idp *domain.ExternalIDP) {
for idx, idp = range wm.ExternalIDPs {
func (wm *UserWriteModel) IDPLinkByID(idpID, externalUserID string) (idx int, idp *domain.UserIDPLink) {
for idx, idp = range wm.IDPLinks {
if idp.IDPConfigID == idpID && idp.ExternalUserID == externalUserID {
return idx, idp
}

View File

@@ -1078,7 +1078,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
),
),
eventFromEventPusher(
user.NewHumanExternalIDPAddedEvent(context.Background(),
user.NewUserIDPLinkAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"idpConfigID",
"displayName",
@@ -1107,7 +1107,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
),
},
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("idpConfigID", "externalUserID")),
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("idpConfigID", "externalUserID")),
),
),
},