mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-10 08:13:58 +00:00
fix: clean up writemodels user v3
This commit is contained in:
parent
7ce0ebd07f
commit
4efe7d1786
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"))
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"))
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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"))
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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"))
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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"))
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user