fix: clean up writemodels user v3

This commit is contained in:
Stefan Benz 2024-09-25 19:58:26 +02:00
parent 7ce0ebd07f
commit 4efe7d1786
No known key found for this signature in database
GPG Key ID: 071AA751ED4F9D31
14 changed files with 391 additions and 247 deletions

View File

@ -3,8 +3,6 @@ package user
import (
"context"
"github.com/muhlemmer/gu"
resource_object "github.com/zitadel/zitadel/internal/api/grpc/resources/object/v3alpha"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
@ -61,7 +59,7 @@ func (s *Server) RequestPasswordReset(ctx context.Context, req *user.RequestPass
}
return &user.RequestPasswordResetResponse{
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_ORG, details.ResourceOwner),
VerificationCode: gu.Ptr(schemauser.PlainCode),
VerificationCode: schemauser.PlainCode,
}, nil
}

View File

@ -66,7 +66,7 @@ func (c *Commands) CreateSchemaUser(ctx context.Context, user *CreateSchemaUser)
return nil, err
}
events, codeEmail, codePhone, err := writeModel.NewCreated(ctx,
events, codeEmail, codePhone, err := writeModel.NewCreate(ctx,
schemaWriteModel,
user.Data,
user.Email,
@ -151,10 +151,8 @@ func (c *Commands) ChangeSchemaUser(ctx context.Context, user *ChangeSchemaUser)
if err != nil {
return nil, err
}
if !writeModel.Exists() {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-Nn8CRVlkeZ", "Errors.User.NotFound")
}
// use already used schemaID, if no new schemaID is defined
schemaID := writeModel.SchemaID
if user.SchemaUser != nil && user.SchemaUser.SchemaID != "" {
schemaID = user.SchemaUser.SchemaID
@ -205,7 +203,7 @@ func existingSchema(ctx context.Context, c *Commands, resourceOwner, id string)
return nil, err
}
if !writeModel.Exists() {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists")
return nil, zerrors.ThrowNotFound(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists")
}
return writeModel, nil
}

View File

@ -110,7 +110,7 @@ func TestCommands_ChangeSchemaUserEmail(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-nJ0TQFuRmP", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -416,7 +416,7 @@ func TestCommands_VerifySchemaUserEmail(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-qbGyMPvjvj", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -749,7 +749,7 @@ func TestCommands_ResendSchemaUserEmailCode(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-EajeF6ypOV", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},

View File

@ -215,7 +215,7 @@ func (wm *UserV3WriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(eventtypes...).Builder()
}
func (wm *UserV3WriteModel) NewCreated(
func (wm *UserV3WriteModel) NewCreate(
ctx context.Context,
schemaWM *UserSchemaWriteModel,
data json.RawMessage,
@ -223,11 +223,11 @@ func (wm *UserV3WriteModel) NewCreated(
phone *Phone,
code func(context.Context) (*EncryptedCode, error),
) (_ []eventstore.Command, codeEmail string, codePhone string, err error) {
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, "", "", err
}
if wm.Exists() {
return nil, "", "", zerrors.ThrowPreconditionFailed(nil, "COMMAND-Nn8CRVlkeZ", "Errors.User.AlreadyExists")
if err := wm.NotExists(); err != nil {
return nil, "", "", err
}
schemaID, schemaRevision, err := wm.validateData(ctx, data, schemaWM)
if err != nil {
@ -315,11 +315,11 @@ func (wm *UserV3WriteModel) NewUpdate(
phone *Phone,
code func(context.Context) (*EncryptedCode, error),
) (_ []eventstore.Command, codeEmail string, codePhone string, err error) {
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, "", "", err
}
if !wm.Exists() {
return nil, "", "", zerrors.ThrowPreconditionFailed(nil, "COMMAND-Nn8CRVlkeZ", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, "", "", err
}
events := make([]eventstore.Command, 0)
if user != nil {
@ -390,14 +390,13 @@ func (wm *UserV3WriteModel) newUpdatedEvents(
func (wm *UserV3WriteModel) NewDelete(
ctx context.Context,
) (_ []eventstore.Command, err error) {
if !wm.Exists() {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, err
}
if err := wm.checkPermissionDelete(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionDelete(ctx); err != nil {
return nil, err
}
return []eventstore.Command{schemauser.NewDeletedEvent(ctx, UserV3AggregateFromWriteModel(&wm.WriteModel))}, nil
}
func UserV3AggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
@ -410,37 +409,43 @@ func UserV3AggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggreg
}
}
func (wm *UserV3WriteModel) Exists() bool {
return wm.State != domain.UserStateDeleted && wm.State != domain.UserStateUnspecified
func (wm *UserV3WriteModel) NotExists() error {
if err := wm.Exists(); err != nil {
return nil
}
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-Nn8CRVlkeZ", "Errors.User.AlreadyExists")
}
func (wm *UserV3WriteModel) checkPermissionWrite(
ctx context.Context,
resourceOwner string,
userID string,
) error {
func (wm *UserV3WriteModel) Exists() error {
if wm.State != domain.UserStateDeleted && wm.State != domain.UserStateUnspecified {
return nil
}
return zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound")
}
func (wm *UserV3WriteModel) checkPermissionWrite(ctx context.Context) error {
if wm.writePermissionCheck {
return nil
}
if userID != "" && userID == authz.GetCtxData(ctx).UserID {
if wm.AggregateID == authz.GetCtxData(ctx).UserID {
return nil
}
if err := wm.checkPermission(ctx, domain.PermissionUserWrite, resourceOwner, userID); err != nil {
if err := wm.checkPermission(ctx, domain.PermissionUserWrite, wm.ResourceOwner, wm.AggregateID); err != nil {
return err
}
wm.writePermissionCheck = true
return nil
}
func (wm *UserV3WriteModel) checkPermissionDelete(
ctx context.Context,
resourceOwner string,
userID string,
) error {
if userID != "" && userID == authz.GetCtxData(ctx).UserID {
func (wm *UserV3WriteModel) checkPermissionDelete(ctx context.Context) error {
if wm.AggregateID == authz.GetCtxData(ctx).UserID {
return nil
}
return wm.checkPermission(ctx, domain.PermissionUserDelete, resourceOwner, userID)
return wm.checkPermission(ctx, domain.PermissionUserDelete, wm.ResourceOwner, wm.AggregateID)
}
func (wm *UserV3WriteModel) checkPermissionStateChange(ctx context.Context) error {
return wm.checkPermission(ctx, domain.PermissionUserWrite, wm.ResourceOwner, wm.AggregateID)
}
func (wm *UserV3WriteModel) NewEmailCreate(
@ -448,7 +453,7 @@ func (wm *UserV3WriteModel) NewEmailCreate(
email *Email,
code func(context.Context) (*EncryptedCode, error),
) (_ []eventstore.Command, plainCode string, err error) {
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, "", err
}
if email == nil || wm.Email == string(email.Address) {
@ -483,8 +488,8 @@ func (wm *UserV3WriteModel) NewEmailUpdate(
if !wm.EmailWM {
return nil, "", nil
}
if !wm.Exists() {
return nil, "", zerrors.ThrowNotFound(nil, "COMMAND-nJ0TQFuRmP", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, "", err
}
return wm.NewEmailCreate(ctx, email, code)
}
@ -496,10 +501,10 @@ func (wm *UserV3WriteModel) NewEmailVerify(
if !wm.EmailWM {
return nil, nil
}
if !wm.Exists() {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-qbGyMPvjvj", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, err
}
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, err
}
if wm.EmailCode == nil {
@ -526,10 +531,10 @@ func (wm *UserV3WriteModel) NewResendEmailCode(
if !wm.EmailWM {
return nil, "", nil
}
if !wm.Exists() {
return nil, "", zerrors.ThrowNotFound(nil, "COMMAND-EajeF6ypOV", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, "", err
}
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, "", err
}
if wm.EmailCode == nil {
@ -569,7 +574,7 @@ func (wm *UserV3WriteModel) NewPhoneCreate(
phone *Phone,
code func(context.Context) (*EncryptedCode, error),
) (_ []eventstore.Command, plainCode string, err error) {
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, "", err
}
if phone == nil || wm.Phone == string(phone.Number) {
@ -604,8 +609,8 @@ func (wm *UserV3WriteModel) NewPhoneUpdate(
if !wm.PhoneWM {
return nil, "", nil
}
if !wm.Exists() {
return nil, "", zerrors.ThrowNotFound(nil, "COMMAND-b33QAVgel6", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, "", err
}
return wm.NewPhoneCreate(ctx, phone, code)
}
@ -617,10 +622,10 @@ func (wm *UserV3WriteModel) NewPhoneVerify(
if !wm.PhoneWM {
return nil, nil
}
if !wm.Exists() {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-bx2OLtgGNS", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, err
}
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, err
}
if wm.PhoneCode == nil {
@ -646,10 +651,10 @@ func (wm *UserV3WriteModel) NewResendPhoneCode(
if !wm.PhoneWM {
return nil, "", nil
}
if !wm.Exists() {
return nil, "", zerrors.ThrowNotFound(nil, "COMMAND-z8Bu9vuL9s", "Errors.User.NotFound")
if err := wm.Exists(); err != nil {
return nil, "", err
}
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, "", err
}
if wm.PhoneCode == nil {
@ -681,3 +686,59 @@ func (wm *UserV3WriteModel) newPhoneCodeAddedEvent(
isReturnCode,
), plainCode, nil
}
func (wm *UserV3WriteModel) NewLock(ctx context.Context) (_ []eventstore.Command, err error) {
if err := wm.Exists(); err != nil {
return nil, err
}
// can only be locked when not already locked
if wm.Locked {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-G4LOrnjY7q", "Errors.User.NotFound")
}
if err := wm.checkPermissionStateChange(ctx); err != nil {
return nil, err
}
return []eventstore.Command{schemauser.NewLockedEvent(ctx, UserV3AggregateFromWriteModel(&wm.WriteModel))}, nil
}
func (wm *UserV3WriteModel) NewUnlock(ctx context.Context) (_ []eventstore.Command, err error) {
if err := wm.Exists(); err != nil {
return nil, err
}
// can only be unlocked when locked
if !wm.Locked {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-gpBv46Lh9m", "Errors.User.NotFound")
}
if err := wm.checkPermissionStateChange(ctx); err != nil {
return nil, err
}
return []eventstore.Command{schemauser.NewUnlockedEvent(ctx, UserV3AggregateFromWriteModel(&wm.WriteModel))}, nil
}
func (wm *UserV3WriteModel) NewDeactivate(ctx context.Context) (_ []eventstore.Command, err error) {
if err := wm.Exists(); err != nil {
return nil, err
}
// can only be deactivated when active
if wm.State != domain.UserStateActive {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-Ob6lR5iFTe", "Errors.User.NotFound")
}
if err := wm.checkPermissionStateChange(ctx); err != nil {
return nil, err
}
return []eventstore.Command{schemauser.NewDeactivatedEvent(ctx, UserV3AggregateFromWriteModel(&wm.WriteModel))}, nil
}
func (wm *UserV3WriteModel) NewActivate(ctx context.Context) (_ []eventstore.Command, err error) {
if err := wm.Exists(); err != nil {
return nil, err
}
// can only be activated when inactive
if wm.State != domain.UserStateInactive {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-rQjbBr4J3j", "Errors.User.NotFound")
}
if err := wm.checkPermissionStateChange(ctx); err != nil {
return nil, err
}
return []eventstore.Command{schemauser.NewActivatedEvent(ctx, UserV3AggregateFromWriteModel(&wm.WriteModel))}, nil
}

View File

@ -6,7 +6,6 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/repository/user/authenticator"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -46,6 +45,7 @@ func (c *Commands) SetSchemaUserPassword(ctx context.Context, user *SetSchemaUse
}
schemaUser := &schemaUserPassword{
Create: true,
ResourceOwner: user.ResourceOwner,
UserID: user.UserID,
VerificationCode: user.VerificationCode,
@ -54,27 +54,15 @@ func (c *Commands) SetSchemaUserPassword(ctx context.Context, user *SetSchemaUse
EncodedPasswordHash: user.EncodedPasswordHash,
}
existing, err := c.getSchemaUserPasswordWithVerification(ctx, schemaUser)
writeModel, err := c.getSchemaUserPasswordWithVerification(ctx, schemaUser)
if err != nil {
return nil, err
}
resourceOwner := existing.ResourceOwner
// when no password was set yet
if existing.EncodedHash == "" {
existingUser, err := c.getSchemaUserWMForState(ctx, user.ResourceOwner, user.UserID)
if err != nil {
return nil, err
}
if !existingUser.Exists() {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-TODO", "Errors.User.Password.NotFound")
}
resourceOwner = existingUser.ResourceOwner
}
// If password is provided, let's check if is compliant with the policy.
// If only a encodedPassword is passed, we can skip this.
if user.Password != "" {
if err = c.checkPasswordComplexity(ctx, user.Password, resourceOwner); err != nil {
if err = c.checkPasswordComplexity(ctx, user.Password, writeModel.ResourceOwner); err != nil {
return nil, err
}
}
@ -87,18 +75,14 @@ func (c *Commands) SetSchemaUserPassword(ctx context.Context, user *SetSchemaUse
}
}
events, err := c.eventstore.Push(ctx,
authenticator.NewPasswordCreatedEvent(ctx,
&authenticator.NewAggregate(user.UserID, resourceOwner).Aggregate,
existing.UserID,
encodedPassword,
user.ChangeRequired,
),
events, err := writeModel.NewCreate(ctx,
encodedPassword,
user.ChangeRequired,
)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(events), nil
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
type RequestSchemaUserPasswordReset struct {
@ -107,64 +91,48 @@ type RequestSchemaUserPasswordReset struct {
URLTemplate string
NotificationType domain.NotificationType
PlainCode string
PlainCode *string
ReturnCode bool
}
func (c *Commands) RequestSchemaUserPasswordReset(ctx context.Context, user *RequestSchemaUserPasswordReset) (_ *domain.ObjectDetails, err error) {
existing, err := c.getSchemaUserPasswordExists(ctx, user.ResourceOwner, user.UserID)
if err != nil {
return nil, err
}
if existing.EncodedHash == "" {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-TODO", "Errors.User.Password.NotFound")
}
code, err := c.newEncryptedCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordResetCode, c.userEncryption) //nolint:staticcheck
writeModel, err := existsSchemaUserPasswordWithPermission(ctx, c, user.ResourceOwner, user.UserID)
if err != nil {
return nil, err
}
events, err := c.eventstore.Push(ctx,
authenticator.NewPasswordCodeAddedEvent(ctx,
&authenticator.NewAggregate(existing.UserID, existing.ResourceOwner).Aggregate,
code.Crypted,
code.Expiry,
user.NotificationType,
user.URLTemplate,
user.ReturnCode,
),
events, plainCode, err := writeModel.NewAddCode(ctx,
user.NotificationType,
user.URLTemplate,
user.ReturnCode,
func(ctx context.Context) (*EncryptedCode, error) {
return c.newEncryptedCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordResetCode, c.userEncryption) //nolint:staticcheck
},
)
if err != nil {
return nil, err
}
if user.ReturnCode {
user.PlainCode = code.Plain
if plainCode != "" {
user.PlainCode = &plainCode
}
return pushedEventsToObjectDetails(events), nil
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) DeleteSchemaUserPassword(ctx context.Context, resourceOwner, id string) (_ *domain.ObjectDetails, err error) {
existing, err := c.getSchemaUserPasswordExists(ctx, resourceOwner, id)
writeModel, err := existsSchemaUserPasswordWithPermission(ctx, c, resourceOwner, id)
if err != nil {
return nil, err
}
if existing.EncodedHash == "" {
return nil, zerrors.ThrowNotFound(nil, "TODO", "TODO")
}
events, err := c.eventstore.Push(ctx,
authenticator.NewPasswordDeletedEvent(ctx,
&authenticator.NewAggregate(id, existing.ResourceOwner).Aggregate,
),
)
events, err := writeModel.NewDelete(ctx)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(events), nil
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
type schemaUserPassword struct {
Create bool
ResourceOwner string
UserID string
VerificationCode string
@ -173,18 +141,37 @@ type schemaUserPassword struct {
EncodedPasswordHash string
}
func (c *Commands) getSchemaUserPasswordExists(ctx context.Context, resourceOwner, id string) (*PasswordV3WriteModel, error) {
return c.getSchemaUserPasswordWithVerification(ctx, &schemaUserPassword{ResourceOwner: resourceOwner, UserID: id})
func (c *Commands) getSchemaUserPasswordWM(ctx context.Context, resourceOwner, id string) (*PasswordV3WriteModel, error) {
writeModel := NewPasswordV3WriteModel(resourceOwner, id, c.checkPermission)
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
return nil, err
}
return writeModel, nil
}
func existsSchemaUserPasswordWithPermission(ctx context.Context, c *Commands, resourceOwner, id string) (*PasswordV3WriteModel, error) {
writeModel, err := c.getSchemaUserPasswordWithVerification(ctx, &schemaUserPassword{ResourceOwner: resourceOwner, UserID: id})
if err != nil {
return nil, err
}
return writeModel, writeModel.Exists()
}
func (c *Commands) getSchemaUserPasswordWithVerification(ctx context.Context, user *schemaUserPassword) (*PasswordV3WriteModel, error) {
if user.UserID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-PoSU5BOZCi", "Errors.IDMissing")
}
writeModel := NewPasswordV3WriteModel(user.ResourceOwner, user.UserID)
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
writeModel, err := c.getSchemaUserPasswordWM(ctx, user.ResourceOwner, user.UserID)
if err != nil {
return nil, err
}
if err := writeModel.Exists(); user.Create && err != nil {
schemauser, err := existingSchemaUser(ctx, c, user.ResourceOwner, user.UserID)
if err != nil {
return nil, err
}
writeModel.ResourceOwner = schemauser.ResourceOwner
}
// if no verification is set, the user must have the permission to change the password
verification := c.setSchemaUserPasswordWithPermission(writeModel.UserID, writeModel.ResourceOwner)

View File

@ -1,11 +1,14 @@
package command
import (
"context"
"time"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/user/authenticator"
"github.com/zitadel/zitadel/internal/zerrors"
)
type PasswordV3WriteModel struct {
@ -18,15 +21,22 @@ type PasswordV3WriteModel struct {
Code *crypto.CryptoValue
CodeCreationDate time.Time
CodeExpiry time.Duration
checkPermission domain.PermissionCheck
}
func NewPasswordV3WriteModel(resourceOwner, id string) *PasswordV3WriteModel {
func (wm *PasswordV3WriteModel) GetWriteModel() *eventstore.WriteModel {
return &wm.WriteModel
}
func NewPasswordV3WriteModel(resourceOwner, id string, checkPermission domain.PermissionCheck) *PasswordV3WriteModel {
return &PasswordV3WriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: id,
ResourceOwner: resourceOwner,
},
UserID: id,
UserID: id,
checkPermission: checkPermission,
}
}
@ -64,3 +74,60 @@ func (wm *PasswordV3WriteModel) Query() *eventstore.SearchQueryBuilder {
authenticator.PasswordCodeAddedType,
).Builder()
}
func (wm *PasswordV3WriteModel) NewCreate(
ctx context.Context,
encodeHash string,
changeRequired bool,
) ([]eventstore.Command, error) {
return []eventstore.Command{
authenticator.NewPasswordCreatedEvent(ctx,
AuthenticatorAggregateFromWriteModel(wm.GetWriteModel()),
wm.UserID,
encodeHash,
changeRequired,
),
}, nil
}
func (wm *PasswordV3WriteModel) NewAddCode(
ctx context.Context,
notificationType domain.NotificationType,
urlTemplate string,
codeReturned bool,
code func(context.Context) (*EncryptedCode, error),
) (_ []eventstore.Command, plainCode string, err error) {
crypt, err := code(ctx)
if err != nil {
return nil, "", err
}
events := []eventstore.Command{
authenticator.NewPasswordCodeAddedEvent(ctx,
AuthenticatorAggregateFromWriteModel(wm.GetWriteModel()),
crypt.Crypted,
crypt.Expiry,
notificationType,
urlTemplate,
codeReturned,
),
}
if codeReturned {
plainCode = crypt.Plain
}
return events, plainCode, nil
}
func (wm *PasswordV3WriteModel) NewDelete(ctx context.Context) ([]eventstore.Command, error) {
if err := wm.Exists(); err != nil {
return nil, err
}
return []eventstore.Command{authenticator.NewPasswordDeletedEvent(ctx, AuthenticatorAggregateFromWriteModel(wm.GetWriteModel()))}, nil
}
func (wm *PasswordV3WriteModel) Exists() error {
if wm.EncodedHash == "" {
return zerrors.ThrowNotFound(nil, "COMMAND-Joi3utDPIh", "Errors.User.Password.NotFound")
}
return nil
}

View File

@ -121,7 +121,7 @@ func TestCommands_SetSchemaUserPassword(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-TODO", "Errors.User.Password.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -130,6 +130,7 @@ func TestCommands_SetSchemaUserPassword(t *testing.T) {
fields{
eventstore: expectEventstore(
expectFilter(),
filterSchemaUserExisting(),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
@ -609,7 +610,7 @@ func TestCommands_RequestSchemaUserPasswordReset(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-TODO", "Errors.User.Password.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-Joi3utDPIh", "Errors.User.Password.NotFound"))
},
},
},
@ -768,7 +769,8 @@ func TestCommands_RequestSchemaUserPasswordReset(t *testing.T) {
assertObjectDetails(t, tt.res.details, details)
}
if tt.res.plainCode != "" {
assert.Equal(t, tt.res.plainCode, tt.args.user.PlainCode)
assert.NotNil(t, tt.args.user.PlainCode)
assert.Equal(t, tt.res.plainCode, *tt.args.user.PlainCode)
}
})
}
@ -824,7 +826,7 @@ func TestCommands_DeleteSchemaUserPassword(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "TODO", "TODO"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-Joi3utDPIh", "Errors.User.Password.NotFound"))
},
},
},
@ -858,7 +860,7 @@ func TestCommands_DeleteSchemaUserPassword(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "TODO", "TODO"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-Joi3utDPIh", "Errors.User.Password.NotFound"))
},
},
},

View File

@ -90,7 +90,7 @@ func TestCommands_ChangeSchemaUserPhone(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-b33QAVgel6", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -394,7 +394,7 @@ func TestCommands_VerifySchemaUserPhone(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-bx2OLtgGNS", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -722,7 +722,7 @@ func TestCommands_ResendSchemaUserPhoneCode(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-z8Bu9vuL9s", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},

View File

@ -4,7 +4,6 @@ import (
"context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/repository/user/schemauser"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -16,18 +15,11 @@ func (c *Commands) LockSchemaUser(ctx context.Context, resourceOwner, id string)
if err != nil {
return nil, err
}
if !writeModel.Exists() || writeModel.Locked {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-G4LOrnjY7q", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
events, err := writeModel.NewLock(ctx)
if err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewLockedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) UnlockSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
@ -38,18 +30,11 @@ func (c *Commands) UnlockSchemaUser(ctx context.Context, resourceOwner, id strin
if err != nil {
return nil, err
}
if !writeModel.Exists() || !writeModel.Locked {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-gpBv46Lh9m", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
events, err := writeModel.NewUnlock(ctx)
if err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewUnlockedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) DeactivateSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
@ -60,18 +45,11 @@ func (c *Commands) DeactivateSchemaUser(ctx context.Context, resourceOwner, id s
if err != nil {
return nil, err
}
if writeModel.State != domain.UserStateActive {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-Ob6lR5iFTe", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
events, err := writeModel.NewDeactivate(ctx)
if err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewDeactivatedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) ActivateSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
@ -82,22 +60,11 @@ func (c *Commands) ActivateSchemaUser(ctx context.Context, resourceOwner, id str
if err != nil {
return nil, err
}
if writeModel.State != domain.UserStateInactive {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-rQjbBr4J3j", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
events, err := writeModel.NewActivate(ctx)
if err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewActivatedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) checkPermissionUpdateUserState(ctx context.Context, resourceOwner, userID string) error {
return c.checkPermission(ctx, domain.PermissionUserWrite, resourceOwner, userID)
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) getSchemaUserWMForState(ctx context.Context, resourceOwner, id string) (*UserV3WriteModel, error) {
@ -107,3 +74,11 @@ func (c *Commands) getSchemaUserWMForState(ctx context.Context, resourceOwner, i
}
return writeModel, nil
}
func existingSchemaUser(ctx context.Context, c *Commands, resourceOwner, id string) (*UserV3WriteModel, error) {
writeModel, err := c.getSchemaUserWMForState(ctx, resourceOwner, id)
if err != nil {
return nil, err
}
return writeModel, writeModel.Exists()
}

View File

@ -66,7 +66,7 @@ func TestCommandSide_LockSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-G4LOrnjY7q", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -100,7 +100,7 @@ func TestCommandSide_LockSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-G4LOrnjY7q", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -274,7 +274,7 @@ func TestCommandSide_UnlockSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-gpBv46Lh9m", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -308,7 +308,7 @@ func TestCommandSide_UnlockSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-gpBv46Lh9m", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -487,7 +487,7 @@ func TestCommandSide_DeactivateSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-Ob6lR5iFTe", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -521,7 +521,7 @@ func TestCommandSide_DeactivateSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-Ob6lR5iFTe", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -695,7 +695,7 @@ func TestCommandSide_ReactivateSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-rQjbBr4J3j", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -729,7 +729,7 @@ func TestCommandSide_ReactivateSchemaUser(t *testing.T) {
},
res: res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-rQjbBr4J3j", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},

View File

@ -97,7 +97,7 @@ func TestCommands_CreateSchemaUser(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists"))
},
},
},
@ -1008,7 +1008,7 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists"))
},
},
},

View File

@ -4,7 +4,6 @@ import (
"context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/repository/user/authenticator"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -17,91 +16,60 @@ type AddUsername struct {
}
func (c *Commands) AddUsername(ctx context.Context, username *AddUsername) (*domain.ObjectDetails, error) {
existing, err := existingSchemaUserWithPermission(ctx, c, username.ResourceOwner, username.UserID)
if username.UserID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-aS3Vz5t6BS", "Errors.IDMissing")
}
schemauser, err := existingSchemaUser(ctx, c, username.ResourceOwner, username.UserID)
if err != nil {
return nil, err
}
_, err = existingSchema(ctx, c, "", schemauser.SchemaID)
if err != nil {
return nil, err
}
// TODO check for possible authenticators
id, err := c.idGenerator.Next()
if err != nil {
return nil, err
}
events, err := c.eventstore.Push(ctx,
authenticator.NewUsernameCreatedEvent(ctx,
&authenticator.NewAggregate(id, existing.ResourceOwner).Aggregate,
existing.AggregateID,
username.IsOrgSpecific,
username.Username,
),
)
writeModel, err := c.getSchemaUsernameWM(ctx, schemauser.ResourceOwner, schemauser.AggregateID, id)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(events), nil
events, err := writeModel.NewCreate(ctx, username.IsOrgSpecific, username.Username)
if err != nil {
return nil, err
}
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) DeleteUsername(ctx context.Context, resourceOwner, userID, id string) (_ *domain.ObjectDetails, err error) {
existing, err := c.getSchemaUsernameExistsWithPermission(ctx, resourceOwner, userID, id)
if err != nil {
return nil, err
}
events, err := c.eventstore.Push(ctx,
authenticator.NewUsernameDeletedEvent(ctx,
&authenticator.NewAggregate(id, existing.ResourceOwner).Aggregate,
existing.IsOrgSpecific,
existing.Username,
),
)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(events), nil
}
func (c *Commands) getSchemaUsernameExistsWithPermission(ctx context.Context, resourceOwner, userID, id string) (*UsernameV3WriteModel, error) {
if userID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-J6ybG5WZiy", "Errors.IDMissing")
}
if id == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-PoSU5BOZCi", "Errors.IDMissing")
}
writeModel := NewUsernameV3WriteModel(resourceOwner, userID, id)
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
writeModel, err := c.getSchemaUsernameWM(ctx, resourceOwner, userID, id)
if err != nil {
return nil, err
}
if writeModel.Username == "" {
return nil, zerrors.ThrowNotFound(nil, "TODO", "TODO")
}
if err := c.checkPermissionUpdateUser(ctx, writeModel.ResourceOwner, writeModel.UserID); err != nil {
events, err := writeModel.NewDelete(ctx)
if err != nil {
return nil, err
}
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
}
func (c *Commands) getSchemaUsernameWM(ctx context.Context, resourceOwner, userID, id string) (*UsernameV3WriteModel, error) {
writeModel := NewUsernameV3WriteModel(resourceOwner, userID, id, c.checkPermission)
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
return nil, err
}
return writeModel, nil
}
func existingSchemaUserWithPermission(ctx context.Context, c *Commands, resourceOwner, userID string) (*UserV3WriteModel, error) {
if userID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-aS3Vz5t6BS", "Errors.IDMissing")
}
existingUser, err := c.getSchemaUserWMForState(ctx, resourceOwner, userID)
if err != nil {
return nil, err
}
if !existingUser.Exists() {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-6T2xrOHxTx", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUser(ctx, existingUser.ResourceOwner, existingUser.AggregateID); err != nil {
return nil, err
}
existingSchema, err := c.getSchemaWriteModelByID(ctx, "", existingUser.SchemaID)
if err != nil {
return nil, err
}
if !existingSchema.Exists() {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-6T2xrOHxTx", "TODO")
}
// TODO possible authenticators check
return existingUser, nil
}

View File

@ -1,8 +1,13 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/user/authenticator"
"github.com/zitadel/zitadel/internal/zerrors"
)
type UsernameV3WriteModel struct {
@ -10,15 +15,22 @@ type UsernameV3WriteModel struct {
UserID string
Username string
IsOrgSpecific bool
checkPermission domain.PermissionCheck
}
func NewUsernameV3WriteModel(resourceOwner, userID, id string) *UsernameV3WriteModel {
func (wm *UsernameV3WriteModel) GetWriteModel() *eventstore.WriteModel {
return &wm.WriteModel
}
func NewUsernameV3WriteModel(resourceOwner, userID, id string, checkPermission domain.PermissionCheck) *UsernameV3WriteModel {
return &UsernameV3WriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: id,
ResourceOwner: resourceOwner,
},
UserID: userID,
UserID: userID,
checkPermission: checkPermission,
}
}
@ -52,3 +64,74 @@ func (wm *UsernameV3WriteModel) Query() *eventstore.SearchQueryBuilder {
authenticator.UsernameDeletedType,
).Builder()
}
func (wm *UsernameV3WriteModel) checkPermissionWrite(ctx context.Context) error {
if wm.UserID == authz.GetCtxData(ctx).UserID {
return nil
}
if err := wm.checkPermission(ctx, domain.PermissionUserWrite, wm.ResourceOwner, wm.UserID); err != nil {
return err
}
return nil
}
func (wm *UsernameV3WriteModel) NewCreate(
ctx context.Context,
isOrgSpecific bool,
username string,
) ([]eventstore.Command, error) {
if err := wm.NotExists(); err != nil {
return nil, err
}
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, err
}
return []eventstore.Command{
authenticator.NewUsernameCreatedEvent(ctx,
AuthenticatorAggregateFromWriteModel(wm.GetWriteModel()),
wm.UserID,
isOrgSpecific,
username,
),
}, nil
}
func (wm *UsernameV3WriteModel) NewDelete(ctx context.Context) ([]eventstore.Command, error) {
if err := wm.Exists(); err != nil {
return nil, err
}
if err := wm.checkPermissionWrite(ctx); err != nil {
return nil, err
}
return []eventstore.Command{
authenticator.NewUsernameDeletedEvent(ctx,
AuthenticatorAggregateFromWriteModel(wm.GetWriteModel()),
wm.IsOrgSpecific,
wm.Username,
),
}, nil
}
func (wm *UsernameV3WriteModel) Exists() error {
if wm.Username == "" {
return zerrors.ThrowNotFound(nil, "TODO", "TODO")
}
return nil
}
func (wm *UsernameV3WriteModel) NotExists() error {
if err := wm.Exists(); err != nil {
return nil
}
return zerrors.ThrowAlreadyExists(nil, "TODO", "TODO")
}
func AuthenticatorAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return &eventstore.Aggregate{
ID: wm.AggregateID,
Type: authenticator.AggregateType,
ResourceOwner: wm.ResourceOwner,
InstanceID: wm.InstanceID,
Version: authenticator.AggregateVersion,
}
}

View File

@ -123,7 +123,7 @@ func TestCommands_AddUsername(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-6T2xrOHxTx", "Errors.User.NotFound"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-syHyCsGmvM", "Errors.User.NotFound"))
},
},
},
@ -132,8 +132,11 @@ func TestCommands_AddUsername(t *testing.T) {
fields{
eventstore: expectEventstore(
filterSchemaUserExisting(),
filterSchemaExisting(),
expectFilter(),
),
checkPermission: newMockPermissionCheckNotAllowed(),
idGenerator: mock.ExpectID(t, "username1"),
},
args{
ctx: authz.NewMockContext("instanceID", "", ""),
@ -164,7 +167,7 @@ func TestCommands_AddUsername(t *testing.T) {
},
res{
err: func(err error) bool {
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-6T2xrOHxTx", "TODO"))
return errors.Is(err, zerrors.ThrowNotFound(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists"))
},
},
},
@ -174,6 +177,7 @@ func TestCommands_AddUsername(t *testing.T) {
eventstore: expectEventstore(
filterSchemaUserExisting(),
filterSchemaExisting(),
expectFilter(),
expectPush(
authenticator.NewUsernameCreatedEvent(
context.Background(),
@ -207,6 +211,7 @@ func TestCommands_AddUsername(t *testing.T) {
eventstore: expectEventstore(
filterSchemaUserExisting(),
filterSchemaExisting(),
expectFilter(),
expectPush(
authenticator.NewUsernameCreatedEvent(
context.Background(),