fix(import/export): fix for deactivated user/organization being imported as active (#9992)

This commit is contained in:
Iraq
2025-06-11 13:50:31 +02:00
committed by GitHub
parent 0ae3f2a6ea
commit 77f0a10c1e
11 changed files with 574 additions and 41 deletions

View File

@@ -428,7 +428,7 @@ func (h *AddHuman) shouldAddInitCode() bool {
}
// Deprecated: use commands.AddUserHuman
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, links []*domain.UserIDPLink, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, state *domain.UserState, links []*domain.UserIDPLink, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -455,10 +455,32 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
}
}
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, links, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
events, userAgg, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, links, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
if err != nil {
return nil, nil, err
}
if state != nil {
var event eventstore.Command
switch *state {
case domain.UserStateInactive:
event = user.NewUserDeactivatedEvent(ctx, userAgg)
case domain.UserStateLocked:
event = user.NewUserLockedEvent(ctx, userAgg)
case domain.UserStateDeleted:
// users are never imported if deleted
case domain.UserStateActive:
// added because of the linter
case domain.UserStateSuspend:
// added because of the linter
case domain.UserStateInitial:
// added because of the linter
case domain.UserStateUnspecified:
// added because of the linter
}
if event != nil {
events = append(events, event)
}
}
pushedEvents, err := c.eventstore.Push(ctx, events...)
if err != nil {
return nil, nil, err
@@ -479,48 +501,48 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
return writeModelToHuman(addedHuman), passwordlessCode, nil
}
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, links []*domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, links []*domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, userAgg *eventstore.Aggregate, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if orgID == "" {
return nil, nil, nil, "", zerrors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.Org.Empty")
return nil, nil, nil, nil, "", zerrors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.Org.Empty")
}
if err = human.Normalize(); err != nil {
return nil, nil, nil, "", err
return nil, nil, nil, nil, "", err
}
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, links, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
events, userAgg, humanWriteModel, err = c.createHuman(ctx, orgID, human, links, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
if err != nil {
return nil, nil, nil, "", err
return nil, nil, nil, nil, "", err
}
if passwordless {
var codeEvent eventstore.Command
codeEvent, passwordlessCodeWriteModel, code, err = c.humanAddPasswordlessInitCode(ctx, human.AggregateID, orgID, true, passwordlessCodeGenerator)
if err != nil {
return nil, nil, nil, "", err
return nil, nil, nil, nil, "", err
}
events = append(events, codeEvent)
}
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
return events, userAgg, humanWriteModel, passwordlessCodeWriteModel, code, nil
}
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, links []*domain.UserIDPLink, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, addedHuman *HumanWriteModel, err error) {
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, links []*domain.UserIDPLink, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, userAgg *eventstore.Aggregate, addedHuman *HumanWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if err = human.CheckDomainPolicy(domainPolicy); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
human.Username = strings.TrimSpace(human.Username)
human.EmailAddress = human.EmailAddress.Normalize()
if err = c.userValidateDomain(ctx, orgID, human.Username, domainPolicy.UserLoginMustBeDomain); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
if human.AggregateID == "" {
userID, err := c.idGenerator.Next()
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
human.AggregateID = userID
}
@@ -528,20 +550,21 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
human.EnsureDisplayName()
if human.Password != nil {
if err := human.HashPasswordIfExisting(ctx, pwPolicy, c.userPasswordHasher, human.Password.ChangeRequired); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
}
addedHuman = NewHumanWriteModel(human.AggregateID, orgID)
//TODO: adlerhurst maybe we could simplify the code below
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
// TODO: adlerhurst maybe we could simplify the code below
userAgg = UserAggregateFromWriteModelCtx(ctx, &addedHuman.WriteModel)
events = append(events, createAddHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
for _, link := range links {
event, err := c.addUserIDPLink(ctx, userAgg, link, false)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
events = append(events, event)
}
@@ -549,7 +572,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
if human.IsInitialState(passwordless, len(links) > 0) {
initCode, err := domain.NewInitUserCode(initCodeGenerator)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
events = append(events, user.NewHumanInitialCodeAddedEvent(ctx, userAgg, initCode.Code, initCode.Expiry, ""))
} else {
@@ -558,7 +581,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
} else {
emailCode, _, err := domain.NewEmailCode(emailCodeGenerator)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
events = append(events, user.NewHumanEmailCodeAddedEvent(ctx, userAgg, emailCode.Code, emailCode.Expiry, ""))
}
@@ -567,14 +590,14 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
phoneCode, generatorID, err := c.newPhoneCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode, c.userEncryption, c.defaultSecretGenerators.PhoneVerificationCode) //nolint:staticcheck
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
events = append(events, user.NewHumanPhoneCodeAddedEvent(ctx, userAgg, phoneCode.CryptedCode(), phoneCode.CodeExpiry(), generatorID))
} else if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified {
events = append(events, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
}
return events, addedHuman, nil
return events, userAgg, addedHuman, nil
}
func (c *Commands) HumanSkipMFAInit(ctx context.Context, userID, resourceowner string) (err error) {