mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
feat: user service v2 create, update and remove (#6996)
* feat: user service v2 remove user * feat: user service v2 add user human * feat: user service v2 change user human * feat: user service v2 change user human unit tests * feat: user service v2 reactivate, deactivate, lock, unlock user * feat: user service v2 integration tests * fix: merge back origin/main * lint: linter corrections * fix: move permission check for isVerfied and password change * fix: add deprecated notices and other review comments * fix: consistent naming in proto * fix: errors package renaming * fix: remove / delete user renaming in integration test * fix: machine user status changes through user v2 api * fix: linting changes * fix: linting changes * fix: changes from review * fix: changes from review * fix: changes from review * fix: changes from review * fix: changes from review --------- Co-authored-by: Tim Möhlmann <tim+github@zitadel.com> Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func (s *Server) UpdateMyPassword(ctx context.Context, req *auth_pb.UpdateMyPasswordRequest) (*auth_pb.UpdateMyPasswordResponse, error) {
|
||||
ctxData := authz.GetCtxData(ctx)
|
||||
objectDetails, err := s.command.ChangePassword(ctx, ctxData.ResourceOwner, ctxData.UserID, req.OldPassword, req.NewPassword, "")
|
||||
objectDetails, err := s.command.ChangePassword(ctx, ctxData.ResourceOwner, ctxData.UserID, req.OldPassword, req.NewPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -53,9 +53,9 @@ func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest)
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
case *user.SetPasswordRequest_CurrentPassword:
|
||||
details, err = s.command.ChangePassword(ctx, resourceOwner, req.GetUserId(), v.CurrentPassword, req.GetNewPassword().GetPassword(), "")
|
||||
details, err = s.command.ChangePassword(ctx, resourceOwner, req.GetUserId(), v.CurrentPassword, req.GetNewPassword().GetPassword())
|
||||
case *user.SetPasswordRequest_VerificationCode:
|
||||
details, err = s.command.SetPasswordWithVerifyCode(ctx, resourceOwner, req.GetUserId(), v.VerificationCode, req.GetNewPassword().GetPassword(), "")
|
||||
details, err = s.command.SetPasswordWithVerifyCode(ctx, resourceOwner, req.GetUserId(), v.VerificationCode, req.GetNewPassword().GetPassword())
|
||||
case nil:
|
||||
details, err = s.command.SetPassword(ctx, resourceOwner, req.GetUserId(), req.GetNewPassword().GetPassword(), req.GetNewPassword().GetChangeRequired())
|
||||
default:
|
||||
|
@@ -28,7 +28,7 @@ func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest
|
||||
return nil, err
|
||||
}
|
||||
orgID := authz.GetCtxData(ctx).OrgID
|
||||
if err = s.command.AddHuman(ctx, orgID, human, false); err != nil {
|
||||
if err = s.command.AddUserHuman(ctx, orgID, human, false, s.userCodeAlg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddHumanUserResponse{
|
||||
@@ -113,6 +113,172 @@ func genderToDomain(gender user.Gender) domain.Gender {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateHumanUser(ctx context.Context, req *user.UpdateHumanUserRequest) (_ *user.UpdateHumanUserResponse, err error) {
|
||||
human, err := UpdateUserRequestToChangeHuman(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.command.ChangeUserHuman(ctx, human, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateHumanUserResponse{
|
||||
Details: object.DomainToDetailsPb(human.Details),
|
||||
EmailCode: human.EmailCode,
|
||||
PhoneCode: human.PhoneCode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) LockUser(ctx context.Context, req *user.LockUserRequest) (_ *user.LockUserResponse, err error) {
|
||||
details, err := s.command.LockUserV2(ctx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.LockUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UnlockUser(ctx context.Context, req *user.UnlockUserRequest) (_ *user.UnlockUserResponse, err error) {
|
||||
details, err := s.command.UnlockUserV2(ctx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UnlockUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateUser(ctx context.Context, req *user.DeactivateUserRequest) (_ *user.DeactivateUserResponse, err error) {
|
||||
details, err := s.command.DeactivateUserV2(ctx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeactivateUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateUser(ctx context.Context, req *user.ReactivateUserRequest) (_ *user.ReactivateUserResponse, err error) {
|
||||
details, err := s.command.ReactivateUserV2(ctx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ReactivateUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ifNotNilPtr[v, p any](value *v, conv func(v) p) *p {
|
||||
var pNil *p
|
||||
if value == nil {
|
||||
return pNil
|
||||
}
|
||||
pVal := conv(*value)
|
||||
return &pVal
|
||||
}
|
||||
|
||||
func UpdateUserRequestToChangeHuman(req *user.UpdateHumanUserRequest) (*command.ChangeHuman, error) {
|
||||
email, err := SetHumanEmailToEmail(req.Email, req.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.ChangeHuman{
|
||||
ID: req.GetUserId(),
|
||||
Username: req.Username,
|
||||
Profile: SetHumanProfileToProfile(req.Profile),
|
||||
Email: email,
|
||||
Phone: SetHumanPhoneToPhone(req.Phone),
|
||||
Password: SetHumanPasswordToPassword(req.Password),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func SetHumanProfileToProfile(profile *user.SetHumanProfile) *command.Profile {
|
||||
if profile == nil {
|
||||
return nil
|
||||
}
|
||||
var firstName *string
|
||||
if profile.GivenName != "" {
|
||||
firstName = &profile.GivenName
|
||||
}
|
||||
var lastName *string
|
||||
if profile.FamilyName != "" {
|
||||
lastName = &profile.FamilyName
|
||||
}
|
||||
return &command.Profile{
|
||||
FirstName: firstName,
|
||||
LastName: lastName,
|
||||
NickName: profile.NickName,
|
||||
DisplayName: profile.DisplayName,
|
||||
PreferredLanguage: ifNotNilPtr(profile.PreferredLanguage, language.Make),
|
||||
Gender: ifNotNilPtr(profile.Gender, genderToDomain),
|
||||
}
|
||||
}
|
||||
|
||||
func SetHumanEmailToEmail(email *user.SetHumanEmail, userID string) (*command.Email, error) {
|
||||
if email == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var urlTemplate string
|
||||
if email.GetSendCode() != nil && email.GetSendCode().UrlTemplate != nil {
|
||||
urlTemplate = *email.GetSendCode().UrlTemplate
|
||||
if err := domain.RenderConfirmURLTemplate(io.Discard, urlTemplate, userID, "code", "orgID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &command.Email{
|
||||
Address: domain.EmailAddress(email.Email),
|
||||
Verified: email.GetIsVerified(),
|
||||
ReturnCode: email.GetReturnCode() != nil,
|
||||
URLTemplate: urlTemplate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func SetHumanPhoneToPhone(phone *user.SetHumanPhone) *command.Phone {
|
||||
if phone == nil {
|
||||
return nil
|
||||
}
|
||||
return &command.Phone{
|
||||
Number: domain.PhoneNumber(phone.GetPhone()),
|
||||
Verified: phone.GetIsVerified(),
|
||||
ReturnCode: phone.GetReturnCode() != nil,
|
||||
}
|
||||
}
|
||||
|
||||
func SetHumanPasswordToPassword(password *user.SetPassword) *command.Password {
|
||||
if password == nil {
|
||||
return nil
|
||||
}
|
||||
var changeRequired bool
|
||||
var passwordStr *string
|
||||
if password.GetPassword() != nil {
|
||||
passwordStr = &password.GetPassword().Password
|
||||
changeRequired = password.GetPassword().GetChangeRequired()
|
||||
}
|
||||
var hash *string
|
||||
if password.GetHashedPassword() != nil {
|
||||
hash = &password.GetHashedPassword().Hash
|
||||
changeRequired = password.GetHashedPassword().GetChangeRequired()
|
||||
}
|
||||
var code *string
|
||||
if password.GetVerificationCode() != "" {
|
||||
codeT := password.GetVerificationCode()
|
||||
code = &codeT
|
||||
}
|
||||
var oldPassword *string
|
||||
if password.GetCurrentPassword() != "" {
|
||||
oldPasswordT := password.GetCurrentPassword()
|
||||
oldPassword = &oldPasswordT
|
||||
}
|
||||
return &command.Password{
|
||||
PasswordCode: code,
|
||||
OldPassword: oldPassword,
|
||||
Password: passwordStr,
|
||||
EncodedPasswordHash: hash,
|
||||
ChangeRequired: changeRequired,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_ *user.AddIDPLinkResponse, err error) {
|
||||
orgID := authz.GetCtxData(ctx).OrgID
|
||||
details, err := s.command.AddUserIDPLink(ctx, req.UserId, orgID, &command.AddLink{
|
||||
@@ -128,6 +294,92 @@ func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUser(ctx context.Context, req *user.DeleteUserRequest) (_ *user.DeleteUserResponse, err error) {
|
||||
memberships, grants, err := s.removeUserDependencies(ctx, req.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.RemoveUserV2(ctx, req.UserId, memberships, grants...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeleteUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) removeUserDependencies(ctx context.Context, userID string) ([]*command.CascadingMembership, []string, error) {
|
||||
userGrantUserQuery, err := query.NewUserGrantUserIDSearchQuery(userID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{
|
||||
Queries: []query.SearchQuery{userGrantUserQuery},
|
||||
}, true, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
membershipsUserQuery, err := query.NewMembershipUserIDQuery(userID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
memberships, err := s.query.Memberships(ctx, &query.MembershipSearchQuery{
|
||||
Queries: []query.SearchQuery{membershipsUserQuery},
|
||||
}, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return cascadingMemberships(memberships.Memberships), userGrantsToIDs(grants.UserGrants), nil
|
||||
}
|
||||
|
||||
func cascadingMemberships(memberships []*query.Membership) []*command.CascadingMembership {
|
||||
cascades := make([]*command.CascadingMembership, len(memberships))
|
||||
for i, membership := range memberships {
|
||||
cascades[i] = &command.CascadingMembership{
|
||||
UserID: membership.UserID,
|
||||
ResourceOwner: membership.ResourceOwner,
|
||||
IAM: cascadingIAMMembership(membership.IAM),
|
||||
Org: cascadingOrgMembership(membership.Org),
|
||||
Project: cascadingProjectMembership(membership.Project),
|
||||
ProjectGrant: cascadingProjectGrantMembership(membership.ProjectGrant),
|
||||
}
|
||||
}
|
||||
return cascades
|
||||
}
|
||||
|
||||
func cascadingIAMMembership(membership *query.IAMMembership) *command.CascadingIAMMembership {
|
||||
if membership == nil {
|
||||
return nil
|
||||
}
|
||||
return &command.CascadingIAMMembership{IAMID: membership.IAMID}
|
||||
}
|
||||
func cascadingOrgMembership(membership *query.OrgMembership) *command.CascadingOrgMembership {
|
||||
if membership == nil {
|
||||
return nil
|
||||
}
|
||||
return &command.CascadingOrgMembership{OrgID: membership.OrgID}
|
||||
}
|
||||
func cascadingProjectMembership(membership *query.ProjectMembership) *command.CascadingProjectMembership {
|
||||
if membership == nil {
|
||||
return nil
|
||||
}
|
||||
return &command.CascadingProjectMembership{ProjectID: membership.ProjectID}
|
||||
}
|
||||
func cascadingProjectGrantMembership(membership *query.ProjectGrantMembership) *command.CascadingProjectGrantMembership {
|
||||
if membership == nil {
|
||||
return nil
|
||||
}
|
||||
return &command.CascadingProjectGrantMembership{ProjectID: membership.ProjectID, GrantID: membership.GrantID}
|
||||
}
|
||||
|
||||
func userGrantsToIDs(userGrants []*query.UserGrant) []string {
|
||||
converted := make([]string, len(userGrants))
|
||||
for i, grant := range userGrants {
|
||||
converted[i] = grant.ID
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *user.StartIdentityProviderIntentRequest) (_ *user.StartIdentityProviderIntentResponse, err error) {
|
||||
switch t := req.GetContent().(type) {
|
||||
case *user.StartIdentityProviderIntentRequest_Urls:
|
||||
|
@@ -540,6 +540,896 @@ func TestServer_AddHumanUser(t *testing.T) {
|
||||
if tt.want.GetEmailCode() != "" {
|
||||
assert.NotEmpty(t, got.GetEmailCode())
|
||||
}
|
||||
if tt.want.GetPhoneCode() != "" {
|
||||
assert.NotEmpty(t, got.GetPhoneCode())
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_UpdateHumanUser(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.UpdateHumanUserRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare func(request *user.UpdateHumanUserRequest) error
|
||||
args args
|
||||
want *user.UpdateHumanUserResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not exisiting",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
request.UserId = "notexisiting"
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Username: gu.Ptr("changed"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "change username, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Username: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change profile, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Profile: &user.SetHumanProfile{
|
||||
GivenName: "Donald",
|
||||
FamilyName: "Duck",
|
||||
NickName: gu.Ptr("Dukkie"),
|
||||
DisplayName: gu.Ptr("Donald Duck"),
|
||||
PreferredLanguage: gu.Ptr("en"),
|
||||
Gender: user.Gender_GENDER_DIVERSE.Enum(),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change email, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Email: &user.SetHumanEmail{
|
||||
Email: "changed@test.com",
|
||||
Verification: &user.SetHumanEmail_IsVerified{IsVerified: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change email, code, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Email: &user.SetHumanEmail{
|
||||
Email: "changed@test.com",
|
||||
Verification: &user.SetHumanEmail_ReturnCode{},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
EmailCode: gu.Ptr("something"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change phone, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Phone: &user.SetHumanPhone{
|
||||
Phone: "+41791234567",
|
||||
Verification: &user.SetHumanPhone_IsVerified{IsVerified: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change phone, code, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Phone: &user.SetHumanPhone{
|
||||
Phone: "+41791234568",
|
||||
Verification: &user.SetHumanPhone_ReturnCode{},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
PhoneCode: gu.Ptr("something"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change password, code, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
resp, err := Client.PasswordReset(CTX, &user.PasswordResetRequest{
|
||||
UserId: userID,
|
||||
Medium: &user.PasswordResetRequest_ReturnCode{
|
||||
ReturnCode: &user.ReturnPasswordResetCode{},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Password.Verification = &user.SetPassword_VerificationCode{
|
||||
VerificationCode: resp.GetVerificationCode(),
|
||||
}
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Password: &user.SetPassword{
|
||||
PasswordType: &user.SetPassword_Password{
|
||||
Password: &user.Password{
|
||||
Password: "Password1!",
|
||||
ChangeRequired: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change hashed password, code, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
resp, err := Client.PasswordReset(CTX, &user.PasswordResetRequest{
|
||||
UserId: userID,
|
||||
Medium: &user.PasswordResetRequest_ReturnCode{
|
||||
ReturnCode: &user.ReturnPasswordResetCode{},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Password.Verification = &user.SetPassword_VerificationCode{
|
||||
VerificationCode: resp.GetVerificationCode(),
|
||||
}
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Password: &user.SetPassword{
|
||||
PasswordType: &user.SetPassword_HashedPassword{
|
||||
HashedPassword: &user.HashedPassword{
|
||||
Hash: "$2y$12$hXUrnqdq1RIIYZ2HPytIIe5lXdIvbhqrTvdPsSF7o.jFh817Z6lwm",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change hashed password, code, not supported",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
resp, err := Client.PasswordReset(CTX, &user.PasswordResetRequest{
|
||||
UserId: userID,
|
||||
Medium: &user.PasswordResetRequest_ReturnCode{
|
||||
ReturnCode: &user.ReturnPasswordResetCode{},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Password = &user.SetPassword{
|
||||
Verification: &user.SetPassword_VerificationCode{
|
||||
VerificationCode: resp.GetVerificationCode(),
|
||||
},
|
||||
}
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Password: &user.SetPassword{
|
||||
PasswordType: &user.SetPassword_HashedPassword{
|
||||
HashedPassword: &user.HashedPassword{
|
||||
Hash: "$scrypt$ln=16,r=8,p=1$cmFuZG9tc2FsdGlzaGFyZA$Rh+NnJNo1I6nRwaNqbDm6kmADswD1+7FTKZ7Ln9D8nQ",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "change password, old password, ok",
|
||||
prepare: func(request *user.UpdateHumanUserRequest) error {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
request.UserId = userID
|
||||
|
||||
resp, err := Client.PasswordReset(CTX, &user.PasswordResetRequest{
|
||||
UserId: userID,
|
||||
Medium: &user.PasswordResetRequest_ReturnCode{
|
||||
ReturnCode: &user.ReturnPasswordResetCode{},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pw := "Password1."
|
||||
_, err = Client.SetPassword(CTX, &user.SetPasswordRequest{
|
||||
UserId: userID,
|
||||
NewPassword: &user.Password{
|
||||
Password: pw,
|
||||
ChangeRequired: true,
|
||||
},
|
||||
Verification: &user.SetPasswordRequest_VerificationCode{
|
||||
VerificationCode: resp.GetVerificationCode(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Password.Verification = &user.SetPassword_CurrentPassword{
|
||||
CurrentPassword: pw,
|
||||
}
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UpdateHumanUserRequest{
|
||||
Password: &user.SetPassword{
|
||||
PasswordType: &user.SetPassword_Password{
|
||||
Password: &user.Password{
|
||||
Password: "Password1!",
|
||||
ChangeRequired: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &user.UpdateHumanUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.UpdateHumanUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
if tt.want.GetEmailCode() != "" {
|
||||
assert.NotEmpty(t, got.GetEmailCode())
|
||||
}
|
||||
if tt.want.GetPhoneCode() != "" {
|
||||
assert.NotEmpty(t, got.GetPhoneCode())
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_LockUser(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.LockUserRequest
|
||||
prepare func(request *user.LockUserRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *user.LockUserResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "lock, not existing",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.LockUserRequest{
|
||||
UserId: "notexisting",
|
||||
},
|
||||
func(request *user.LockUserRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "lock, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.LockUserRequest{},
|
||||
func(request *user.LockUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &user.LockUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "lock machine, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.LockUserRequest{},
|
||||
func(request *user.LockUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &user.LockUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "lock, already locked",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.LockUserRequest{},
|
||||
func(request *user.LockUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.LockUser(CTX, &user.LockUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "lock machine, already locked",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.LockUserRequest{},
|
||||
func(request *user.LockUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.LockUser(CTX, &user.LockUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.LockUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_UnLockUser(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.UnlockUserRequest
|
||||
prepare func(request *user.UnlockUserRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *user.UnlockUserResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "unlock, not existing",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.UnlockUserRequest{
|
||||
UserId: "notexisting",
|
||||
},
|
||||
func(request *user.UnlockUserRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "unlock, not locked",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.UnlockUserRequest{},
|
||||
prepare: func(request *user.UnlockUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "unlock machine, not locked",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.UnlockUserRequest{},
|
||||
prepare: func(request *user.UnlockUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "unlock, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.UnlockUserRequest{},
|
||||
prepare: func(request *user.UnlockUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.LockUser(CTX, &user.LockUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.UnlockUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unlock machine, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.UnlockUserRequest{},
|
||||
prepare: func(request *user.UnlockUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.LockUser(CTX, &user.LockUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.UnlockUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.UnlockUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeactivateUser(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.DeactivateUserRequest
|
||||
prepare func(request *user.DeactivateUserRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *user.DeactivateUserResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "deactivate, not existing",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.DeactivateUserRequest{
|
||||
UserId: "notexisting",
|
||||
},
|
||||
func(request *user.DeactivateUserRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "deactivate, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.DeactivateUserRequest{},
|
||||
func(request *user.DeactivateUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &user.DeactivateUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deactivate machine, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.DeactivateUserRequest{},
|
||||
func(request *user.DeactivateUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &user.DeactivateUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deactivate, already deactivated",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.DeactivateUserRequest{},
|
||||
func(request *user.DeactivateUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.DeactivateUser(CTX, &user.DeactivateUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "deactivate machine, already deactivated",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.DeactivateUserRequest{},
|
||||
func(request *user.DeactivateUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.DeactivateUser(CTX, &user.DeactivateUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.DeactivateUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_ReactivateUser(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.ReactivateUserRequest
|
||||
prepare func(request *user.ReactivateUserRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *user.ReactivateUserResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "reactivate, not existing",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.ReactivateUserRequest{
|
||||
UserId: "notexisting",
|
||||
},
|
||||
func(request *user.ReactivateUserRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "reactivate, not deactivated",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.ReactivateUserRequest{},
|
||||
prepare: func(request *user.ReactivateUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "reactivate machine, not deactivated",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.ReactivateUserRequest{},
|
||||
prepare: func(request *user.ReactivateUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "reactivate, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.ReactivateUserRequest{},
|
||||
prepare: func(request *user.ReactivateUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.DeactivateUser(CTX, &user.DeactivateUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.ReactivateUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reactivate machine, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.ReactivateUserRequest{},
|
||||
prepare: func(request *user.ReactivateUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
_, err := Client.DeactivateUser(CTX, &user.DeactivateUserRequest{
|
||||
UserId: resp.GetUserId(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.ReactivateUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.ReactivateUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeleteUser(t *testing.T) {
|
||||
projectResp, err := Tester.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.DeleteUserRequest
|
||||
prepare func(request *user.DeleteUserRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *user.DeleteUserResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "remove, not existing",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.DeleteUserRequest{
|
||||
UserId: "notexisting",
|
||||
},
|
||||
func(request *user.DeleteUserRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "remove human, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.DeleteUserRequest{},
|
||||
prepare: func(request *user.DeleteUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.DeleteUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove machine, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.DeleteUserRequest{},
|
||||
prepare: func(request *user.DeleteUserRequest) error {
|
||||
resp := Tester.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.DeleteUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove dependencies, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.DeleteUserRequest{},
|
||||
prepare: func(request *user.DeleteUserRequest) error {
|
||||
resp := Tester.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
Tester.CreateProjectUserGrant(t, CTX, projectResp.GetId(), request.UserId)
|
||||
Tester.CreateProjectMembership(t, CTX, projectResp.GetId(), request.UserId)
|
||||
Tester.CreateOrgMembership(t, CTX, request.UserId)
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.DeleteUserResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.DeleteUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user