mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:37:31 +00:00
feat: New event user (#1156)
* feat: change user command side * feat: change user command side * feat: use states on write model * feat: command and query side in auth api * feat: auth commands * feat: check external idp id * feat: user state check * fix: error messages * fix: is active state
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/v2/command"
|
||||
"github.com/caos/zitadel/internal/v2/query"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
@@ -17,16 +19,20 @@ const (
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
repo repository.Repository
|
||||
command *command.CommandSide
|
||||
query *query.QuerySide
|
||||
repo repository.Repository
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Repository eventsourcing.Config
|
||||
}
|
||||
|
||||
func CreateServer(authRepo repository.Repository) *Server {
|
||||
func CreateServer(command *command.CommandSide, query *query.QuerySide, authRepo repository.Repository) *Server {
|
||||
return &Server{
|
||||
repo: authRepo,
|
||||
command: command,
|
||||
query: query,
|
||||
repo: authRepo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
|
||||
"github.com/caos/zitadel/pkg/grpc/auth"
|
||||
@@ -62,23 +62,24 @@ func (s *Server) GetMyMfas(ctx context.Context, _ *empty.Empty) (*auth.MultiFact
|
||||
}
|
||||
|
||||
func (s *Server) UpdateMyUserProfile(ctx context.Context, request *auth.UpdateUserProfileRequest) (*auth.UserProfile, error) {
|
||||
profile, err := s.repo.ChangeMyProfile(ctx, updateProfileToModel(ctx, request))
|
||||
profile, err := s.command.ChangeHumanProfile(ctx, updateProfileToDomain(ctx, request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return profileFromModel(profile), nil
|
||||
return profileFromDomain(profile), nil
|
||||
}
|
||||
|
||||
func (s *Server) ChangeMyUserName(ctx context.Context, request *auth.ChangeUserNameRequest) (*empty.Empty, error) {
|
||||
return &empty.Empty{}, s.repo.ChangeMyUsername(ctx, request.UserName)
|
||||
ctxData := authz.GetCtxData(ctx)
|
||||
return &empty.Empty{}, s.command.ChangeUsername(ctx, ctxData.OrgID, ctxData.UserID, request.UserName)
|
||||
}
|
||||
|
||||
func (s *Server) ChangeMyUserEmail(ctx context.Context, request *auth.UpdateUserEmailRequest) (*auth.UserEmail, error) {
|
||||
email, err := s.repo.ChangeMyEmail(ctx, updateEmailToModel(ctx, request))
|
||||
email, err := s.command.ChangeHumanEmail(ctx, updateEmailToDomain(ctx, request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return emailFromModel(email), nil
|
||||
return emailFromDomain(email), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyMyUserEmail(ctx context.Context, request *auth.VerifyMyUserEmailRequest) (*empty.Empty, error) {
|
||||
@@ -92,11 +93,11 @@ func (s *Server) ResendMyEmailVerificationMail(ctx context.Context, _ *empty.Emp
|
||||
}
|
||||
|
||||
func (s *Server) ChangeMyUserPhone(ctx context.Context, request *auth.UpdateUserPhoneRequest) (*auth.UserPhone, error) {
|
||||
phone, err := s.repo.ChangeMyPhone(ctx, updatePhoneToModel(ctx, request))
|
||||
phone, err := s.command.ChangeHumanPhone(ctx, updatePhoneToDomain(ctx, request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return phoneFromModel(phone), nil
|
||||
return phoneFromDomain(phone), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyMyUserPhone(ctx context.Context, request *auth.VerifyUserPhoneRequest) (*empty.Empty, error) {
|
||||
|
@@ -3,6 +3,7 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
@@ -52,7 +53,7 @@ func userViewFromModel(user *usr_model.UserView) *auth.UserView {
|
||||
return userView
|
||||
}
|
||||
|
||||
func profileFromModel(profile *usr_model.Profile) *auth.UserProfile {
|
||||
func profileFromDomain(profile *domain.Profile) *auth.UserProfile {
|
||||
creationDate, err := ptypes.TimestampProto(profile.CreationDate)
|
||||
logging.Log("GRPC-56t5s").OnError(err).Debug("unable to parse timestamp")
|
||||
|
||||
@@ -69,7 +70,7 @@ func profileFromModel(profile *usr_model.Profile) *auth.UserProfile {
|
||||
DisplayName: profile.DisplayName,
|
||||
NickName: profile.NickName,
|
||||
PreferredLanguage: profile.PreferredLanguage.String(),
|
||||
Gender: genderFromModel(profile.Gender),
|
||||
Gender: genderFromDomain(profile.Gender),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,36 +82,37 @@ func profileViewFromModel(profile *usr_model.Profile) *auth.UserProfileView {
|
||||
logging.Log("GRPC-9sujE").OnError(err).Debug("unable to parse timestamp")
|
||||
|
||||
return &auth.UserProfileView{
|
||||
Id: profile.AggregateID,
|
||||
CreationDate: creationDate,
|
||||
ChangeDate: changeDate,
|
||||
Sequence: profile.Sequence,
|
||||
FirstName: profile.FirstName,
|
||||
LastName: profile.LastName,
|
||||
DisplayName: profile.DisplayName,
|
||||
NickName: profile.NickName,
|
||||
PreferredLanguage: profile.PreferredLanguage.String(),
|
||||
Gender: genderFromModel(profile.Gender),
|
||||
Id: profile.AggregateID,
|
||||
CreationDate: creationDate,
|
||||
ChangeDate: changeDate,
|
||||
Sequence: profile.Sequence,
|
||||
FirstName: profile.FirstName,
|
||||
LastName: profile.LastName,
|
||||
DisplayName: profile.DisplayName,
|
||||
NickName: profile.NickName,
|
||||
PreferredLanguage: profile.PreferredLanguage.String(),
|
||||
//TODO: Use converter
|
||||
Gender: auth.Gender(profile.Gender),
|
||||
LoginNames: profile.LoginNames,
|
||||
PreferredLoginName: profile.PreferredLoginName,
|
||||
}
|
||||
}
|
||||
|
||||
func updateProfileToModel(ctx context.Context, u *auth.UpdateUserProfileRequest) *usr_model.Profile {
|
||||
func updateProfileToDomain(ctx context.Context, u *auth.UpdateUserProfileRequest) *domain.Profile {
|
||||
preferredLanguage, err := language.Parse(u.PreferredLanguage)
|
||||
logging.Log("GRPC-lk73L").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("language malformed")
|
||||
|
||||
return &usr_model.Profile{
|
||||
return &domain.Profile{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID},
|
||||
FirstName: u.FirstName,
|
||||
LastName: u.LastName,
|
||||
NickName: u.NickName,
|
||||
PreferredLanguage: preferredLanguage,
|
||||
Gender: genderToModel(u.Gender),
|
||||
Gender: genderToDomain(u.Gender),
|
||||
}
|
||||
}
|
||||
|
||||
func emailFromModel(email *usr_model.Email) *auth.UserEmail {
|
||||
func emailFromDomain(email *domain.Email) *auth.UserEmail {
|
||||
creationDate, err := ptypes.TimestampProto(email.CreationDate)
|
||||
logging.Log("GRPC-sdoi3").OnError(err).Debug("unable to parse timestamp")
|
||||
|
||||
@@ -144,14 +146,14 @@ func emailViewFromModel(email *usr_model.Email) *auth.UserEmailView {
|
||||
}
|
||||
}
|
||||
|
||||
func updateEmailToModel(ctx context.Context, e *auth.UpdateUserEmailRequest) *usr_model.Email {
|
||||
return &usr_model.Email{
|
||||
func updateEmailToDomain(ctx context.Context, e *auth.UpdateUserEmailRequest) *domain.Email {
|
||||
return &domain.Email{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID},
|
||||
EmailAddress: e.Email,
|
||||
}
|
||||
}
|
||||
|
||||
func phoneFromModel(phone *usr_model.Phone) *auth.UserPhone {
|
||||
func phoneFromDomain(phone *domain.Phone) *auth.UserPhone {
|
||||
creationDate, err := ptypes.TimestampProto(phone.CreationDate)
|
||||
logging.Log("GRPC-kjn5J").OnError(err).Debug("unable to parse timestamp")
|
||||
|
||||
@@ -185,8 +187,8 @@ func phoneViewFromModel(phone *usr_model.Phone) *auth.UserPhoneView {
|
||||
}
|
||||
}
|
||||
|
||||
func updatePhoneToModel(ctx context.Context, e *auth.UpdateUserPhoneRequest) *usr_model.Phone {
|
||||
return &usr_model.Phone{
|
||||
func updatePhoneToDomain(ctx context.Context, e *auth.UpdateUserPhoneRequest) *domain.Phone {
|
||||
return &domain.Phone{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID},
|
||||
PhoneNumber: e.Phone,
|
||||
}
|
||||
@@ -332,29 +334,29 @@ func userStateFromModel(state usr_model.UserState) auth.UserState {
|
||||
}
|
||||
}
|
||||
|
||||
func genderFromModel(gender usr_model.Gender) auth.Gender {
|
||||
func genderFromDomain(gender domain.Gender) auth.Gender {
|
||||
switch gender {
|
||||
case usr_model.GenderFemale:
|
||||
case domain.GenderFemale:
|
||||
return auth.Gender_GENDER_FEMALE
|
||||
case usr_model.GenderMale:
|
||||
case domain.GenderMale:
|
||||
return auth.Gender_GENDER_MALE
|
||||
case usr_model.GenderDiverse:
|
||||
case domain.GenderDiverse:
|
||||
return auth.Gender_GENDER_DIVERSE
|
||||
default:
|
||||
return auth.Gender_GENDER_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func genderToModel(gender auth.Gender) usr_model.Gender {
|
||||
func genderToDomain(gender auth.Gender) domain.Gender {
|
||||
switch gender {
|
||||
case auth.Gender_GENDER_FEMALE:
|
||||
return usr_model.GenderFemale
|
||||
return domain.GenderFemale
|
||||
case auth.Gender_GENDER_MALE:
|
||||
return usr_model.GenderMale
|
||||
return domain.GenderMale
|
||||
case auth.Gender_GENDER_DIVERSE:
|
||||
return usr_model.GenderDiverse
|
||||
return domain.GenderDiverse
|
||||
default:
|
||||
return usr_model.GenderUnspecified
|
||||
return domain.GenderUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,16 +17,17 @@ func humanViewFromModel(user *usr_model.HumanView) *auth.HumanView {
|
||||
DisplayName: user.DisplayName,
|
||||
NickName: user.NickName,
|
||||
PreferredLanguage: user.PreferredLanguage,
|
||||
Gender: genderFromModel(user.Gender),
|
||||
Email: user.Email,
|
||||
IsEmailVerified: user.IsEmailVerified,
|
||||
Phone: user.Phone,
|
||||
IsPhoneVerified: user.IsPhoneVerified,
|
||||
Country: user.Country,
|
||||
Locality: user.Locality,
|
||||
PostalCode: user.PostalCode,
|
||||
Region: user.Region,
|
||||
StreetAddress: user.StreetAddress,
|
||||
PasswordChanged: passwordChanged,
|
||||
//TODO: add converter
|
||||
Gender: auth.Gender(user.Gender),
|
||||
Email: user.Email,
|
||||
IsEmailVerified: user.IsEmailVerified,
|
||||
Phone: user.Phone,
|
||||
IsPhoneVerified: user.IsPhoneVerified,
|
||||
Country: user.Country,
|
||||
Locality: user.Locality,
|
||||
PostalCode: user.PostalCode,
|
||||
Region: user.Region,
|
||||
StreetAddress: user.StreetAddress,
|
||||
PasswordChanged: passwordChanged,
|
||||
}
|
||||
}
|
||||
|
@@ -52,7 +52,7 @@ func (s *Server) IsUserUnique(ctx context.Context, request *management.UniqueUse
|
||||
}
|
||||
|
||||
func (s *Server) CreateUser(ctx context.Context, in *management.CreateUserRequest) (*management.UserResponse, error) {
|
||||
user, err := s.command.AddUser(ctx, userCreateToDomain(in))
|
||||
user, err := s.command.AddUser(ctx, authz.GetCtxData(ctx).OrgID, userCreateToDomain(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -113,7 +113,7 @@ func (s *Server) GetUserProfile(ctx context.Context, in *management.UserID) (*ma
|
||||
}
|
||||
|
||||
func (s *Server) ChangeUserUserName(ctx context.Context, request *management.UpdateUserUserNameRequest) (*empty.Empty, error) {
|
||||
return &empty.Empty{}, s.user.ChangeUsername(ctx, request.Id, request.UserName)
|
||||
return &empty.Empty{}, s.command.ChangeUsername(ctx, authz.GetCtxData(ctx).OrgID, request.Id, request.UserName)
|
||||
}
|
||||
|
||||
func (s *Server) UpdateUserProfile(ctx context.Context, request *management.UpdateUserProfileRequest) (*management.UserProfile, error) {
|
||||
@@ -141,7 +141,7 @@ func (s *Server) ChangeUserEmail(ctx context.Context, request *management.Update
|
||||
}
|
||||
|
||||
func (s *Server) ResendEmailVerificationMail(ctx context.Context, in *management.UserID) (*empty.Empty, error) {
|
||||
err := s.user.CreateEmailVerificationCode(ctx, in.Id)
|
||||
err := s.command.CreateHumanEmailVerificationCode(ctx, in.Id)
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
||||
@@ -154,20 +154,20 @@ func (s *Server) GetUserPhone(ctx context.Context, in *management.UserID) (*mana
|
||||
}
|
||||
|
||||
func (s *Server) ChangeUserPhone(ctx context.Context, request *management.UpdateUserPhoneRequest) (*management.UserPhone, error) {
|
||||
phone, err := s.user.ChangePhone(ctx, updatePhoneToModel(request))
|
||||
phone, err := s.command.ChangeHumanPhone(ctx, updatePhoneToDomain(request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return phoneFromModel(phone), nil
|
||||
return phoneFromDomain(phone), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveUserPhone(ctx context.Context, userID *management.UserID) (*empty.Empty, error) {
|
||||
err := s.user.RemovePhone(ctx, userID.Id)
|
||||
err := s.command.RemoveHumanPhone(ctx, userID.Id)
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
||||
func (s *Server) ResendPhoneVerificationCode(ctx context.Context, in *management.UserID) (*empty.Empty, error) {
|
||||
err := s.user.CreatePhoneVerificationCode(ctx, in.Id)
|
||||
err := s.command.CreateHumanPhoneVerificationCode(ctx, in.Id)
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
||||
@@ -188,18 +188,16 @@ func (s *Server) UpdateUserAddress(ctx context.Context, request *management.Upda
|
||||
}
|
||||
|
||||
func (s *Server) SendSetPasswordNotification(ctx context.Context, request *management.SetPasswordNotificationRequest) (*empty.Empty, error) {
|
||||
err := s.user.RequestSetPassword(ctx, request.Id, notifyTypeToModel(request.Type))
|
||||
err := s.command.RequestSetPassword(ctx, request.Id, notifyTypeToDomain(request.Type))
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
||||
func (s *Server) SetInitialPassword(ctx context.Context, request *management.PasswordRequest) (*empty.Empty, error) {
|
||||
_, err := s.user.SetOneTimePassword(ctx, passwordRequestToModel(request))
|
||||
return &empty.Empty{}, err
|
||||
return &empty.Empty{}, s.command.SetOneTimePassword(ctx, authz.GetCtxData(ctx).OrgID, request.Id, request.Password)
|
||||
}
|
||||
|
||||
func (s *Server) ResendInitialMail(ctx context.Context, request *management.InitialMailRequest) (*empty.Empty, error) {
|
||||
err := s.user.ResendInitialMail(ctx, request.Id, request.Email)
|
||||
return &empty.Empty{}, err
|
||||
return &empty.Empty{}, s.command.ResendInitialMail(ctx, request.Id, request.Email)
|
||||
}
|
||||
|
||||
func (s *Server) SearchUserExternalIDPs(ctx context.Context, request *management.ExternalIDPSearchRequest) (*management.ExternalIDPSearchResponse, error) {
|
||||
@@ -211,8 +209,7 @@ func (s *Server) SearchUserExternalIDPs(ctx context.Context, request *management
|
||||
}
|
||||
|
||||
func (s *Server) RemoveExternalIDP(ctx context.Context, request *management.ExternalIDPRemoveRequest) (*empty.Empty, error) {
|
||||
err := s.user.RemoveExternalIDP(ctx, externalIDPRemoveToModel(request))
|
||||
return &empty.Empty{}, err
|
||||
return &empty.Empty{}, s.command.RemoveHumanExternalIDP(ctx, externalIDPRemoveToDomain(request))
|
||||
}
|
||||
|
||||
func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.UserMultiFactors, error) {
|
||||
@@ -224,13 +221,11 @@ func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*m
|
||||
}
|
||||
|
||||
func (s *Server) RemoveMfaOTP(ctx context.Context, userID *management.UserID) (*empty.Empty, error) {
|
||||
err := s.user.RemoveOTP(ctx, userID.Id)
|
||||
return &empty.Empty{}, err
|
||||
return &empty.Empty{}, s.command.RemoveHumanOTP(ctx, userID.Id)
|
||||
}
|
||||
|
||||
func (s *Server) RemoveMfaU2F(ctx context.Context, webAuthNTokenID *management.WebAuthNTokenID) (*empty.Empty, error) {
|
||||
err := s.user.RemoveU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id)
|
||||
return &empty.Empty{}, err
|
||||
return &empty.Empty{}, s.command.RemoveHumanU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id)
|
||||
}
|
||||
|
||||
func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID) (_ *management.WebAuthNTokens, err error) {
|
||||
@@ -242,8 +237,7 @@ func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID)
|
||||
}
|
||||
|
||||
func (s *Server) RemovePasswordless(ctx context.Context, id *management.WebAuthNTokenID) (*empty.Empty, error) {
|
||||
err := s.user.RemovePasswordless(ctx, id.UserId, id.Id)
|
||||
return &empty.Empty{}, err
|
||||
return &empty.Empty{}, s.command.RemoveHumanPasswordless(ctx, id.UserId, id.Id)
|
||||
}
|
||||
|
||||
func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) {
|
||||
|
@@ -76,11 +76,11 @@ func externalIDPSearchRequestToModel(request *management.ExternalIDPSearchReques
|
||||
}
|
||||
}
|
||||
|
||||
func externalIDPRemoveToModel(idp *management.ExternalIDPRemoveRequest) *usr_model.ExternalIDP {
|
||||
return &usr_model.ExternalIDP{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: idp.UserId},
|
||||
IDPConfigID: idp.IdpConfigId,
|
||||
UserID: idp.ExternalUserId,
|
||||
func externalIDPRemoveToDomain(idp *management.ExternalIDPRemoveRequest) *domain.ExternalIDP {
|
||||
return &domain.ExternalIDP{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: idp.UserId},
|
||||
IDPConfigID: idp.IdpConfigId,
|
||||
ExternalUserID: idp.ExternalUserId,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ func updateEmailToDomain(e *management.UpdateUserEmailRequest) *domain.Email {
|
||||
}
|
||||
}
|
||||
|
||||
func phoneFromModel(phone *usr_model.Phone) *management.UserPhone {
|
||||
func phoneFromDomain(phone *domain.Phone) *management.UserPhone {
|
||||
creationDate, err := ptypes.TimestampProto(phone.CreationDate)
|
||||
logging.Log("GRPC-ps9ws").OnError(err).Debug("unable to parse timestamp")
|
||||
|
||||
@@ -339,8 +339,8 @@ func phoneViewFromModel(phone *usr_model.Phone) *management.UserPhoneView {
|
||||
IsPhoneVerified: phone.IsPhoneVerified,
|
||||
}
|
||||
}
|
||||
func updatePhoneToModel(e *management.UpdateUserPhoneRequest) *usr_model.Phone {
|
||||
return &usr_model.Phone{
|
||||
func updatePhoneToDomain(e *management.UpdateUserPhoneRequest) *domain.Phone {
|
||||
return &domain.Phone{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: e.Id},
|
||||
PhoneNumber: e.Phone,
|
||||
IsPhoneVerified: e.IsPhoneVerified,
|
||||
@@ -510,14 +510,14 @@ func mfaFromModel(mfa *usr_model.MultiFactor) *management.UserMultiFactor {
|
||||
}
|
||||
}
|
||||
|
||||
func notifyTypeToModel(state management.NotificationType) usr_model.NotificationType {
|
||||
func notifyTypeToDomain(state management.NotificationType) domain.NotificationType {
|
||||
switch state {
|
||||
case management.NotificationType_NOTIFICATIONTYPE_EMAIL:
|
||||
return usr_model.NotificationTypeEmail
|
||||
return domain.NotificationTypeEmail
|
||||
case management.NotificationType_NOTIFICATIONTYPE_SMS:
|
||||
return usr_model.NotificationTypeSms
|
||||
return domain.NotificationTypeSms
|
||||
default:
|
||||
return usr_model.NotificationTypeEmail
|
||||
return domain.NotificationTypeEmail
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user