From 320679467b9978d093e7101b9eeea7946306f8d4 Mon Sep 17 00:00:00 2001 From: Fabi <38692350+fgerschwiler@users.noreply.github.com> Date: Mon, 8 Feb 2021 11:30:30 +0100 Subject: [PATCH] feat: User login commands (#1228) * feat: change login to command side * feat: change login to command side * fix: fix push on user * feat: user command side * feat: sign out * feat: command side login * feat: command side login * feat: fix register user * feat: fix register user * feat: fix web auth n events * feat: add machine keys * feat: send codes * feat: move authrequest to domain * feat: move authrequest to domain * feat: webauthn working * feat: external users * feat: external users login * feat: notify users * fix: tests * feat: cascade remove user grants on project remove * fix: webauthn * fix: pr requests * fix: register human with member * fix: fix bugs * fix: fix bugs --- cmd/zitadel/main.go | 6 +- .../eventsourcing/eventstore/user.go | 70 ------ .../repository/eventsourcing/repository.go | 7 - .../api/grpc/admin/login_policy_converter.go | 4 +- internal/api/grpc/auth/user.go | 16 +- .../grpc/management/login_policy_converter.go | 4 +- internal/api/grpc/management/project.go | 7 +- internal/api/grpc/management/user.go | 6 +- .../grpc/management/user_grant_converter.go | 8 + internal/api/grpc/management/user_machine.go | 7 +- .../grpc/management/user_machine_converter.go | 36 +-- internal/api/oidc/auth_request.go | 8 +- internal/api/oidc/auth_request_converter.go | 76 +++--- internal/api/oidc/op.go | 12 +- internal/auth/repository/auth_request.go | 30 ++- .../eventsourcing/eventstore/auth_request.go | 218 ++++++++--------- .../eventsourcing/eventstore/token.go | 32 --- .../eventsourcing/eventstore/user.go | 221 ++--------------- .../repository/eventsourcing/repository.go | 5 +- internal/auth/repository/token.go | 2 - internal/auth/repository/user.go | 31 +-- internal/auth_request/model/next_step.go | 46 ++++ .../auth_request/repository/cache/cache.go | 18 +- .../repository/mock/repository.mock.go | 2 +- .../auth_request/repository/repository.go | 11 +- internal/eventstore/v2/eventstore_test.go | 2 +- internal/eventstore/v2/repository/sql/crdb.go | 2 +- internal/eventstore/v2/search_query.go | 12 +- internal/iam/model/idp_provider_view.go | 61 +++++ internal/iam/model/login_policy_view.go | 56 +++++ .../eventsourcing/eventstore/user.go | 21 -- .../eventsourcing/eventstore/user_grant.go | 16 ++ internal/management/repository/user.go | 2 - internal/management/repository/user_grant.go | 2 + internal/notification/notification.go | 5 +- .../eventsourcing/handler/handler.go | 4 +- .../eventsourcing/handler/notification.go | 49 +++- .../repository/eventsourcing/repository.go | 5 +- .../eventsourcing/spooler/spooler.go | 5 +- internal/static/i18n/de.yaml | 4 + internal/static/i18n/en.yaml | 4 + internal/ui/login/handler/auth_request.go | 6 +- internal/ui/login/handler/callback_handler.go | 5 +- .../login/handler/change_password_handler.go | 8 +- .../login/handler/external_login_handler.go | 72 +++--- .../handler/external_register_handler.go | 59 ++--- .../ui/login/handler/init_password_handler.go | 25 +- .../ui/login/handler/init_user_handler.go | 18 +- .../ui/login/handler/link_users_handler.go | 9 +- internal/ui/login/handler/login_handler.go | 4 +- .../ui/login/handler/mail_verify_handler.go | 17 +- .../ui/login/handler/mfa_init_done_handler.go | 5 +- internal/ui/login/handler/mfa_init_u2f.go | 12 +- .../login/handler/mfa_init_verify_handler.go | 20 +- .../ui/login/handler/mfa_prompt_handler.go | 20 +- .../ui/login/handler/mfa_verify_handler.go | 19 +- .../login/handler/mfa_verify_u2f_handler.go | 19 +- internal/ui/login/handler/password_handler.go | 6 +- .../login/handler/password_reset_handler.go | 12 +- .../handler/passwordless_login_handler.go | 11 +- internal/ui/login/handler/register_handler.go | 48 ++-- .../login/handler/register_option_handler.go | 4 +- .../ui/login/handler/register_org_handler.go | 4 +- internal/ui/login/handler/renderer.go | 72 +++--- .../ui/login/handler/select_user_handler.go | 4 +- .../login/handler/username_change_handler.go | 9 +- .../static/templates/password_reset_done.html | 2 + internal/user/model/user_view.go | 29 +-- .../user/repository/view/model/notify_user.go | 3 + internal/v2/command/iam_converter.go | 2 +- .../v2/command/iam_idp_oidc_config_model.go | 2 +- internal/v2/command/iam_policy_login.go | 4 +- internal/v2/command/org_policy_login.go | 4 +- internal/v2/command/project.go | 17 +- internal/v2/command/setup_step1.go | 2 +- internal/v2/command/user.go | 71 +++++- internal/v2/command/user_converter.go | 26 ++ internal/v2/command/user_grant.go | 3 +- internal/v2/command/user_grant_model.go | 9 +- internal/v2/command/user_human.go | 93 +++++--- internal/v2/command/user_human_email.go | 17 +- internal/v2/command/user_human_email_model.go | 9 +- internal/v2/command/user_human_externalidp.go | 47 ++++ internal/v2/command/user_human_init.go | 104 ++++++++ internal/v2/command/user_human_init_model.go | 89 +++++++ internal/v2/command/user_human_otp.go | 33 ++- internal/v2/command/user_human_otp_model.go | 9 +- internal/v2/command/user_human_password.go | 89 ++++++- .../v2/command/user_human_password_model.go | 19 +- internal/v2/command/user_human_phone.go | 15 +- internal/v2/command/user_human_webauthn.go | 188 ++++++++++++++- .../v2/command/user_human_webauthn_model.go | 188 ++++++++++++--- internal/v2/command/user_machine.go | 2 +- internal/v2/command/user_machine_key.go | 83 +++++++ internal/v2/command/user_machine_key_model.go | 74 ++++++ internal/v2/command/user_model.go | 2 + internal/v2/domain/auth_request.go | 150 ++++++++++++ internal/v2/domain/browser_info.go | 22 ++ internal/v2/domain/human.go | 8 +- internal/v2/domain/human_web_auth_n.go | 14 +- internal/v2/domain/idp_config.go | 9 + internal/v2/domain/machine_key.go | 43 ++++ internal/v2/domain/next_step.go | 149 ++++++++++++ internal/v2/domain/oidc_code_challenge.go | 17 ++ internal/v2/domain/policy_login.go | 15 +- internal/v2/domain/request.go | 54 +++++ internal/v2/domain/roles.go | 1 + internal/v2/domain/token.go | 18 ++ internal/v2/query/query.go | 2 + internal/v2/query/user.go | 11 + internal/v2/query/user_model.go | 5 + .../v2/repository/idpconfig/oidc_config.go | 4 +- .../v2/repository/user/auth_request_info.go | 16 ++ internal/v2/repository/user/eventstore.go | 28 +-- internal/v2/repository/user/human.go | 5 +- .../v2/repository/user/human_external_idp.go | 24 +- internal/v2/repository/user/human_mfa_otp.go | 30 ++- .../repository/user/human_mfa_passwordless.go | 224 ++++++++++++++++++ internal/v2/repository/user/human_mfa_u2f.go | 224 ++++++++++++++++++ .../repository/user/human_mfa_web_auth_n.go | 193 ++------------- internal/v2/repository/user/human_password.go | 32 ++- .../v2/repository/usergrant/user_grant.go | 4 +- internal/webauthn/webauthn.go | 3 +- 123 files changed, 2949 insertions(+), 1212 deletions(-) delete mode 100644 internal/admin/repository/eventsourcing/eventstore/user.go create mode 100644 internal/v2/command/user_human_init.go create mode 100644 internal/v2/command/user_human_init_model.go create mode 100644 internal/v2/command/user_machine_key.go create mode 100644 internal/v2/command/user_machine_key_model.go create mode 100644 internal/v2/domain/auth_request.go create mode 100644 internal/v2/domain/browser_info.go create mode 100644 internal/v2/domain/next_step.go create mode 100644 internal/v2/domain/oidc_code_challenge.go create mode 100644 internal/v2/domain/request.go create mode 100644 internal/v2/domain/token.go create mode 100644 internal/v2/query/user.go create mode 100644 internal/v2/repository/user/auth_request_info.go create mode 100644 internal/v2/repository/user/human_mfa_passwordless.go create mode 100644 internal/v2/repository/user/human_mfa_u2f.go diff --git a/cmd/zitadel/main.go b/cmd/zitadel/main.go index 96b5e22653..09e591c739 100644 --- a/cmd/zitadel/main.go +++ b/cmd/zitadel/main.go @@ -115,7 +115,7 @@ func startZitadel(configPaths []string) { logging.Log("MAIN-s9KOw").OnError(err).Fatal("error starting authz repo") var authRepo *auth_es.EsRepository if *authEnabled || *oidcEnabled || *loginEnabled { - authRepo, err = auth_es.Start(conf.Auth, conf.InternalAuthZ, conf.SystemDefaults, authZRepo) + authRepo, err = auth_es.Start(conf.Auth, conf.InternalAuthZ, conf.SystemDefaults, command, authZRepo) logging.Log("MAIN-9oRw6").OnError(err).Fatal("error starting auth repo") } @@ -123,7 +123,7 @@ func startZitadel(configPaths []string) { startUI(ctx, conf, authRepo, command, query) if *notificationEnabled { - notification.Start(ctx, conf.Notification, conf.SystemDefaults) + notification.Start(ctx, conf.Notification, conf.SystemDefaults, command) } <-ctx.Done() @@ -166,7 +166,7 @@ func startAPI(ctx context.Context, conf *Config, authZRepo *authz_repo.EsReposit apis.RegisterServer(ctx, auth.CreateServer(command, query, authRepo)) } if *oidcEnabled { - op := oidc.NewProvider(ctx, conf.API.OIDC, authRepo, *localDevMode) + op := oidc.NewProvider(ctx, conf.API.OIDC, command, query, authRepo, *localDevMode) apis.RegisterHandler("/oauth/v2", op.HttpHandler()) } apis.Start(ctx) diff --git a/internal/admin/repository/eventsourcing/eventstore/user.go b/internal/admin/repository/eventsourcing/eventstore/user.go deleted file mode 100644 index b465ef091b..0000000000 --- a/internal/admin/repository/eventsourcing/eventstore/user.go +++ /dev/null @@ -1,70 +0,0 @@ -package eventstore - -import ( - "context" - admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view" - "github.com/caos/zitadel/internal/config/systemdefaults" - caos_errs "github.com/caos/zitadel/internal/errors" - iam_view "github.com/caos/zitadel/internal/iam/repository/view/model" - - "github.com/caos/zitadel/internal/api/authz" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" - usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" -) - -type UserRepo struct { - UserEvents *usr_event.UserEventstore - OrgEvents *org_event.OrgEventstore - View *admin_view.View - SystemDefaults systemdefaults.SystemDefaults -} - -func (repo *UserRepo) UserByID(ctx context.Context, id string) (project *usr_model.User, err error) { - return repo.UserEvents.UserByID(ctx, id) -} - -func (repo *UserRepo) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) { - pwPolicy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if caos_errs.IsNotFound(err) { - pwPolicy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return nil, err - } - pwPolicyView := iam_view.PasswordComplexityViewToModel(pwPolicy) - orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if err != nil && caos_errs.IsNotFound(err) { - orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID) - if err != nil { - return nil, err - } - } - orgPolicyView := iam_view.OrgIAMViewToModel(orgPolicy) - return repo.UserEvents.CreateUser(ctx, user, pwPolicyView, orgPolicyView) -} - -func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) { - policyResourceOwner := authz.GetCtxData(ctx).OrgID - if resourceOwner != "" { - policyResourceOwner = resourceOwner - } - pwPolicy, err := repo.View.PasswordComplexityPolicyByAggregateID(policyResourceOwner) - if caos_errs.IsNotFound(err) { - pwPolicy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return nil, err - } - pwPolicyView := iam_view.PasswordComplexityViewToModel(pwPolicy) - - orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(policyResourceOwner) - if caos_errs.IsNotFound(err) { - orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return nil, err - } - orgPolicyView := iam_view.OrgIAMViewToModel(orgPolicy) - return repo.UserEvents.RegisterUser(ctx, user, pwPolicyView, orgPolicyView, resourceOwner) -} diff --git a/internal/admin/repository/eventsourcing/repository.go b/internal/admin/repository/eventsourcing/repository.go index f75c1cf20c..631908c92c 100644 --- a/internal/admin/repository/eventsourcing/repository.go +++ b/internal/admin/repository/eventsourcing/repository.go @@ -28,7 +28,6 @@ type EsRepository struct { eventstore.OrgRepo eventstore.IAMRepository eventstore.AdministratorRepo - eventstore.UserRepo } func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRepository, error) { @@ -86,12 +85,6 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, r AdministratorRepo: eventstore.AdministratorRepo{ View: view, }, - UserRepo: eventstore.UserRepo{ - UserEvents: user, - OrgEvents: org, - View: view, - SystemDefaults: systemDefaults, - }, }, nil } diff --git a/internal/api/grpc/admin/login_policy_converter.go b/internal/api/grpc/admin/login_policy_converter.go index 1ae851b4b4..b0cdd5136e 100644 --- a/internal/api/grpc/admin/login_policy_converter.go +++ b/internal/api/grpc/admin/login_policy_converter.go @@ -12,7 +12,7 @@ import ( func loginPolicyToDomain(policy *admin.DefaultLoginPolicyRequest) *domain.LoginPolicy { return &domain.LoginPolicy{ AllowUsernamePassword: policy.AllowUsernamePassword, - AllowExternalIdp: policy.AllowExternalIdp, + AllowExternalIDP: policy.AllowExternalIdp, AllowRegister: policy.AllowRegister, ForceMFA: policy.ForceMfa, PasswordlessType: passwordlessTypeToDomain(policy.PasswordlessType), @@ -22,7 +22,7 @@ func loginPolicyToDomain(policy *admin.DefaultLoginPolicyRequest) *domain.LoginP func loginPolicyFromDomain(policy *domain.LoginPolicy) *admin.DefaultLoginPolicy { return &admin.DefaultLoginPolicy{ AllowUsernamePassword: policy.AllowUsernamePassword, - AllowExternalIdp: policy.AllowExternalIdp, + AllowExternalIdp: policy.AllowExternalIDP, AllowRegister: policy.AllowRegister, ForceMfa: policy.ForceMFA, PasswordlessType: passwordlessTypeFromDomain(policy.PasswordlessType), diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go index d51ede3e4a..f51a06d5af 100644 --- a/internal/api/grpc/auth/user.go +++ b/internal/api/grpc/auth/user.go @@ -162,19 +162,19 @@ func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *auth.MfaOtpR func (s *Server) VerifyMfaOTP(ctx context.Context, request *auth.VerifyMfaOtp) (*empty.Empty, error) { ctxData := authz.GetCtxData(ctx) - err := s.command.CheckMFAOTPSetup(ctx, ctxData.UserID, request.Code, "", ctxData.ResourceOwner) + err := s.command.HumanCheckMFAOTPSetup(ctx, ctxData.UserID, request.Code, "", ctxData.ResourceOwner) return &empty.Empty{}, err } func (s *Server) RemoveMfaOTP(ctx context.Context, _ *empty.Empty) (_ *empty.Empty, err error) { ctxData := authz.GetCtxData(ctx) - err = s.command.RemoveHumanOTP(ctx, ctxData.UserID, ctxData.OrgID) + err = s.command.HumanRemoveOTP(ctx, ctxData.UserID, ctxData.OrgID) return &empty.Empty{}, err } func (s *Server) AddMyMfaU2F(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) { ctxData := authz.GetCtxData(ctx) - u2f, err := s.command.AddHumanU2F(ctx, ctxData.UserID, ctxData.ResourceOwner, false) + u2f, err := s.command.HumanAddU2FSetup(ctx, ctxData.UserID, ctxData.ResourceOwner, false) if err != nil { return nil, err } @@ -183,13 +183,13 @@ func (s *Server) AddMyMfaU2F(ctx context.Context, _ *empty.Empty) (_ *auth.WebAu func (s *Server) VerifyMyMfaU2F(ctx context.Context, request *auth.VerifyWebAuthN) (*empty.Empty, error) { ctxData := authz.GetCtxData(ctx) - err := s.command.VerifyHumanU2F(ctx, ctxData.UserID, ctxData.OrgID, request.TokenName, "", request.PublicKeyCredential) + err := s.command.HumanVerifyU2FSetup(ctx, ctxData.UserID, ctxData.OrgID, request.TokenName, "", request.PublicKeyCredential) return &empty.Empty{}, err } func (s *Server) RemoveMyMfaU2F(ctx context.Context, id *auth.WebAuthNTokenID) (*empty.Empty, error) { ctxData := authz.GetCtxData(ctx) - err := s.command.RemoveHumanU2F(ctx, ctxData.UserID, id.Id, ctxData.OrgID) + err := s.command.HumanRemoveU2F(ctx, ctxData.UserID, id.Id, ctxData.OrgID) return &empty.Empty{}, err } @@ -203,7 +203,7 @@ func (s *Server) GetMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth func (s *Server) AddMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) { ctxData := authz.GetCtxData(ctx) - u2f, err := s.command.AddHumanPasswordless(ctx, ctxData.UserID, ctxData.ResourceOwner, false) + u2f, err := s.command.HumanAddPasswordlessSetup(ctx, ctxData.UserID, ctxData.ResourceOwner, false) if err != nil { return nil, err } @@ -212,13 +212,13 @@ func (s *Server) AddMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth func (s *Server) VerifyMyPasswordless(ctx context.Context, request *auth.VerifyWebAuthN) (*empty.Empty, error) { ctxData := authz.GetCtxData(ctx) - err := s.command.VerifyHumanPasswordless(ctx, ctxData.UserID, ctxData.OrgID, request.TokenName, "", request.PublicKeyCredential) + err := s.command.HumanHumanPasswordlessSetup(ctx, ctxData.UserID, ctxData.OrgID, request.TokenName, "", request.PublicKeyCredential) return &empty.Empty{}, err } func (s *Server) RemoveMyPasswordless(ctx context.Context, id *auth.WebAuthNTokenID) (*empty.Empty, error) { ctxData := authz.GetCtxData(ctx) - err := s.command.RemoveHumanPasswordless(ctx, ctxData.UserID, id.Id, ctxData.ResourceOwner) + err := s.command.HumanRemovePasswordless(ctx, ctxData.UserID, id.Id, ctxData.ResourceOwner) return &empty.Empty{}, err } diff --git a/internal/api/grpc/management/login_policy_converter.go b/internal/api/grpc/management/login_policy_converter.go index b1aa9816f5..824274fd69 100644 --- a/internal/api/grpc/management/login_policy_converter.go +++ b/internal/api/grpc/management/login_policy_converter.go @@ -20,7 +20,7 @@ func loginPolicyRequestToDomain(ctx context.Context, policy *management.LoginPol AggregateID: authz.GetCtxData(ctx).OrgID, }, AllowUsernamePassword: policy.AllowUsernamePassword, - AllowExternalIdp: policy.AllowExternalIdp, + AllowExternalIDP: policy.AllowExternalIdp, AllowRegister: policy.AllowRegister, ForceMFA: policy.ForceMfa, PasswordlessType: passwordlessTypeToDomain(policy.PasswordlessType), @@ -30,7 +30,7 @@ func loginPolicyRequestToDomain(ctx context.Context, policy *management.LoginPol func loginPolicyFromDomain(policy *domain.LoginPolicy) *management.LoginPolicy { return &management.LoginPolicy{ AllowUsernamePassword: policy.AllowUsernamePassword, - AllowExternalIdp: policy.AllowExternalIdp, + AllowExternalIdp: policy.AllowExternalIDP, AllowRegister: policy.AllowRegister, ChangeDate: timestamppb.New(policy.ChangeDate), ForceMfa: policy.ForceMFA, diff --git a/internal/api/grpc/management/project.go b/internal/api/grpc/management/project.go index 1b114be418..afa3ab1ef8 100644 --- a/internal/api/grpc/management/project.go +++ b/internal/api/grpc/management/project.go @@ -2,7 +2,6 @@ package management import ( "context" - "github.com/golang/protobuf/ptypes/empty" "github.com/caos/zitadel/internal/api/authz" @@ -36,7 +35,11 @@ func (s *Server) ReactivateProject(ctx context.Context, in *management.ProjectID } func (s *Server) RemoveProject(ctx context.Context, in *management.ProjectID) (*empty.Empty, error) { - err := s.command.RemoveProject(ctx, in.Id, authz.GetCtxData(ctx).OrgID) + grants, err := s.usergrant.UserGrantsByProjectID(ctx, in.Id) + if err != nil { + return &empty.Empty{}, err + } + err = s.command.RemoveProject(ctx, in.Id, authz.GetCtxData(ctx).OrgID, userGrantsToIDs(grants)...) return &empty.Empty{}, err } diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index b1309145a3..e10419df85 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -217,11 +217,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) { - return &empty.Empty{}, s.command.RemoveHumanOTP(ctx, userID.Id, authz.GetCtxData(ctx).OrgID) + return &empty.Empty{}, s.command.HumanRemoveOTP(ctx, userID.Id, authz.GetCtxData(ctx).OrgID) } func (s *Server) RemoveMfaU2F(ctx context.Context, webAuthNTokenID *management.WebAuthNTokenID) (*empty.Empty, error) { - return &empty.Empty{}, s.command.RemoveHumanU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id, authz.GetCtxData(ctx).OrgID) + return &empty.Empty{}, s.command.HumanRemoveU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id, authz.GetCtxData(ctx).OrgID) } func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID) (_ *management.WebAuthNTokens, err error) { @@ -233,7 +233,7 @@ func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID) } func (s *Server) RemovePasswordless(ctx context.Context, id *management.WebAuthNTokenID) (*empty.Empty, error) { - return &empty.Empty{}, s.command.RemoveHumanPasswordless(ctx, id.UserId, id.Id, authz.GetCtxData(ctx).OrgID) + return &empty.Empty{}, s.command.HumanRemovePasswordless(ctx, id.UserId, id.Id, authz.GetCtxData(ctx).OrgID) } func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) { diff --git a/internal/api/grpc/management/user_grant_converter.go b/internal/api/grpc/management/user_grant_converter.go index 6273d97243..7feddcd31a 100644 --- a/internal/api/grpc/management/user_grant_converter.go +++ b/internal/api/grpc/management/user_grant_converter.go @@ -177,3 +177,11 @@ func usergrantStateFromDomain(state domain.UserGrantState) management.UserGrantS return management.UserGrantState_USERGRANTSTATE_UNSPECIFIED } } + +func userGrantsToIDs(userGrants []*grant_model.UserGrantView) []string { + converted := make([]string, len(userGrants)) + for i, grant := range userGrants { + converted[i] = grant.ID + } + return converted +} diff --git a/internal/api/grpc/management/user_machine.go b/internal/api/grpc/management/user_machine.go index adb6e5c6eb..6368e5fdf1 100644 --- a/internal/api/grpc/management/user_machine.go +++ b/internal/api/grpc/management/user_machine.go @@ -2,21 +2,22 @@ package management import ( "context" + "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/pkg/grpc/management" "github.com/golang/protobuf/ptypes/empty" ) func (s *Server) AddMachineKey(ctx context.Context, req *management.AddMachineKeyRequest) (*management.AddMachineKeyResponse, error) { - key, err := s.user.AddMachineKey(ctx, addMachineKeyToModel(req)) + key, err := s.command.AddUserMachineKey(ctx, addMachineKeyToDomain(req), authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } - return addMachineKeyFromModel(key), nil + return addMachineKeyFromDomain(key), nil } func (s *Server) DeleteMachineKey(ctx context.Context, req *management.MachineKeyIDRequest) (*empty.Empty, error) { - err := s.user.RemoveMachineKey(ctx, req.UserId, req.KeyId) + err := s.command.RemoveUserMachineKey(ctx, req.UserId, req.KeyId, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } diff --git a/internal/api/grpc/management/user_machine_converter.go b/internal/api/grpc/management/user_machine_converter.go index afa978a5ed..fd1d651d68 100644 --- a/internal/api/grpc/management/user_machine_converter.go +++ b/internal/api/grpc/management/user_machine_converter.go @@ -2,6 +2,7 @@ package management import ( "encoding/json" + "google.golang.org/protobuf/types/known/timestamppb" "time" "github.com/caos/zitadel/internal/api/authz" @@ -75,7 +76,7 @@ func machineKeyViewFromModel(key *usr_model.MachineKeyView) *management.MachineK } } -func addMachineKeyToModel(key *management.AddMachineKeyRequest) *usr_model.MachineKey { +func addMachineKeyToDomain(key *management.AddMachineKeyRequest) *domain.MachineKey { expirationDate := time.Time{} if key.ExpirationDate != nil { var err error @@ -83,20 +84,14 @@ func addMachineKeyToModel(key *management.AddMachineKeyRequest) *usr_model.Machi logging.Log("MANAG-iNshR").OnError(err).Debug("unable to parse expiration date") } - return &usr_model.MachineKey{ + return &domain.MachineKey{ ExpirationDate: expirationDate, - Type: machineKeyTypeToModel(key.Type), + Type: machineKeyTypeToDomain(key.Type), ObjectRoot: models.ObjectRoot{AggregateID: key.UserId}, } } -func addMachineKeyFromModel(key *usr_model.MachineKey) *management.AddMachineKeyResponse { - creationDate, err := ptypes.TimestampProto(key.CreationDate) - logging.Log("MANAG-dlb8m").OnError(err).Debug("unable to parse cretaion date") - - expirationDate, err := ptypes.TimestampProto(key.ExpirationDate) - logging.Log("MANAG-dlb8m").OnError(err).Debug("unable to parse cretaion date") - +func addMachineKeyFromDomain(key *domain.MachineKey) *management.AddMachineKeyResponse { detail, err := json.Marshal(struct { Type string `json:"type"` KeyID string `json:"keyId"` @@ -112,20 +107,29 @@ func addMachineKeyFromModel(key *usr_model.MachineKey) *management.AddMachineKey return &management.AddMachineKeyResponse{ Id: key.KeyID, - CreationDate: creationDate, - ExpirationDate: expirationDate, + CreationDate: timestamppb.New(key.CreationDate), + ExpirationDate: timestamppb.New(key.ExpirationDate), Sequence: key.Sequence, KeyDetails: detail, - Type: machineKeyTypeFromModel(key.Type), + Type: machineKeyTypeFromDomain(key.Type), } } -func machineKeyTypeToModel(typ management.MachineKeyType) usr_model.MachineKeyType { +func machineKeyTypeToDomain(typ management.MachineKeyType) domain.MachineKeyType { switch typ { case management.MachineKeyType_MACHINEKEY_JSON: - return usr_model.MachineKeyTypeJSON + return domain.MachineKeyTypeJSON default: - return usr_model.MachineKeyTypeNONE + return domain.MachineKeyTypeNONE + } +} + +func machineKeyTypeFromDomain(typ domain.MachineKeyType) management.MachineKeyType { + switch typ { + case domain.MachineKeyTypeJSON: + return management.MachineKeyType_MACHINEKEY_JSON + default: + return management.MachineKeyType_MACHINEKEY_UNSPECIFIED } } diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index e1c57c64b5..923bdbc640 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -89,7 +89,7 @@ func (o *OPStorage) CreateToken(ctx context.Context, req op.TokenRequest) (_ str userAgentID = authReq.AgentID applicationID = authReq.ApplicationID } - resp, err := o.repo.CreateToken(ctx, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client + resp, err := o.command.CreateUserToken(ctx, authReq.UserOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client if err != nil { return "", time.Time{}, err } @@ -113,7 +113,11 @@ func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID strin if !ok { return errors.ThrowPreconditionFailed(nil, "OIDC-fso7F", "no user agent id") } - return o.repo.SignOut(ctx, userAgentID) + userIDs, err := o.repo.UserSessionUserIDsByAgentID(ctx, userAgentID) + if err != nil { + return err + } + return o.command.HumansSignOut(ctx, userAgentID, userIDs) } func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) { diff --git a/internal/api/oidc/auth_request_converter.go b/internal/api/oidc/auth_request_converter.go index 5dd4dc15b6..f891bf0be4 100644 --- a/internal/api/oidc/auth_request_converter.go +++ b/internal/api/oidc/auth_request_converter.go @@ -2,6 +2,7 @@ package oidc import ( "context" + "github.com/caos/zitadel/internal/v2/domain" "net" "time" @@ -10,7 +11,6 @@ import ( "golang.org/x/text/language" http_utils "github.com/caos/zitadel/internal/api/http" - "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/errors" ) @@ -22,7 +22,7 @@ const ( ) type AuthRequest struct { - *model.AuthRequest + *domain.AuthRequest } func (a *AuthRequest) GetID() string { @@ -92,26 +92,26 @@ func (a *AuthRequest) GetSubject() string { func (a *AuthRequest) Done() bool { for _, step := range a.PossibleSteps { - if step.Type() == model.NextStepRedirectToCallback { + if step.Type() == domain.NextStepRedirectToCallback { return true } } return false } -func (a *AuthRequest) oidc() *model.AuthRequestOIDC { - return a.Request.(*model.AuthRequestOIDC) +func (a *AuthRequest) oidc() *domain.AuthRequestOIDC { + return a.Request.(*domain.AuthRequestOIDC) } -func AuthRequestFromBusiness(authReq *model.AuthRequest) (_ op.AuthRequest, err error) { - if _, ok := authReq.Request.(*model.AuthRequestOIDC); !ok { +func AuthRequestFromBusiness(authReq *domain.AuthRequest) (_ op.AuthRequest, err error) { + if _, ok := authReq.Request.(*domain.AuthRequestOIDC); !ok { return nil, errors.ThrowInvalidArgument(nil, "OIDC-Haz7A", "auth request is not of type oidc") } return &AuthRequest{authReq}, nil } -func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, userAgentID, userID string) *model.AuthRequest { - return &model.AuthRequest{ +func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, userAgentID, userID string) *domain.AuthRequest { + return &domain.AuthRequest{ AgentID: userAgentID, BrowserInfo: ParseBrowserInfoFromContext(ctx), ApplicationID: authReq.ClientID, @@ -123,7 +123,7 @@ func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, LoginHint: authReq.LoginHint, MaxAuthAge: authReq.MaxAge, UserID: userID, - Request: &model.AuthRequestOIDC{ + Request: &domain.AuthRequestOIDC{ Scopes: authReq.Scopes, ResponseType: ResponseTypeToBusiness(authReq.ResponseType), Nonce: authReq.Nonce, @@ -132,10 +132,10 @@ func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, } } -func ParseBrowserInfoFromContext(ctx context.Context) *model.BrowserInfo { +func ParseBrowserInfoFromContext(ctx context.Context) *domain.BrowserInfo { userAgent, acceptLang := HttpHeadersFromContext(ctx) ip := IpFromContext(ctx) - return &model.BrowserInfo{RemoteIP: ip, UserAgent: userAgent, AcceptLanguage: acceptLang} + return &domain.BrowserInfo{RemoteIP: ip, UserAgent: userAgent, AcceptLanguage: acceptLang} } func HttpHeadersFromContext(ctx context.Context) (userAgent, acceptLang string) { @@ -160,22 +160,22 @@ func IpFromContext(ctx context.Context) net.IP { return net.ParseIP(ipString) } -func PromptToBusiness(prompt oidc.Prompt) model.Prompt { +func PromptToBusiness(prompt oidc.Prompt) domain.Prompt { switch prompt { case oidc.PromptNone: - return model.PromptNone + return domain.PromptNone case oidc.PromptLogin: - return model.PromptLogin + return domain.PromptLogin case oidc.PromptConsent: - return model.PromptConsent + return domain.PromptConsent case oidc.PromptSelectAccount: - return model.PromptSelectAccount + return domain.PromptSelectAccount default: - return model.PromptUnspecified + return domain.PromptUnspecified } } -func ACRValuesToBusiness(values []string) []model.LevelOfAssurance { +func ACRValuesToBusiness(values []string) []domain.LevelOfAssurance { return nil } @@ -190,52 +190,52 @@ func UILocalesToBusiness(tags []language.Tag) []string { return locales } -func ResponseTypeToBusiness(responseType oidc.ResponseType) model.OIDCResponseType { +func ResponseTypeToBusiness(responseType oidc.ResponseType) domain.OIDCResponseType { switch responseType { case oidc.ResponseTypeCode: - return model.OIDCResponseTypeCode + return domain.OIDCResponseTypeCode case oidc.ResponseTypeIDTokenOnly: - return model.OIDCResponseTypeIdToken + return domain.OIDCResponseTypeIDToken case oidc.ResponseTypeIDToken: - return model.OIDCResponseTypeIdTokenToken + return domain.OIDCResponseTypeIDTokenToken default: - return model.OIDCResponseTypeCode + return domain.OIDCResponseTypeCode } } -func ResponseTypeToOIDC(responseType model.OIDCResponseType) oidc.ResponseType { +func ResponseTypeToOIDC(responseType domain.OIDCResponseType) oidc.ResponseType { switch responseType { - case model.OIDCResponseTypeCode: + case domain.OIDCResponseTypeCode: return oidc.ResponseTypeCode - case model.OIDCResponseTypeIdTokenToken: + case domain.OIDCResponseTypeIDTokenToken: return oidc.ResponseTypeIDToken - case model.OIDCResponseTypeIdToken: + case domain.OIDCResponseTypeIDToken: return oidc.ResponseTypeIDTokenOnly default: return oidc.ResponseTypeCode } } -func CodeChallengeToBusiness(challenge string, method oidc.CodeChallengeMethod) *model.OIDCCodeChallenge { +func CodeChallengeToBusiness(challenge string, method oidc.CodeChallengeMethod) *domain.OIDCCodeChallenge { if challenge == "" { return nil } - challengeMethod := model.CodeChallengeMethodPlain + challengeMethod := domain.CodeChallengeMethodPlain if method == oidc.CodeChallengeMethodS256 { - challengeMethod = model.CodeChallengeMethodS256 + challengeMethod = domain.CodeChallengeMethodS256 } - return &model.OIDCCodeChallenge{ + return &domain.OIDCCodeChallenge{ Challenge: challenge, Method: challengeMethod, } } -func CodeChallengeToOIDC(challenge *model.OIDCCodeChallenge) *oidc.CodeChallenge { +func CodeChallengeToOIDC(challenge *domain.OIDCCodeChallenge) *oidc.CodeChallenge { if challenge == nil { return nil } challengeMethod := oidc.CodeChallengeMethodPlain - if challenge.Method == model.CodeChallengeMethodS256 { + if challenge.Method == domain.CodeChallengeMethodS256 { challengeMethod = oidc.CodeChallengeMethodS256 } return &oidc.CodeChallenge{ @@ -244,12 +244,12 @@ func CodeChallengeToOIDC(challenge *model.OIDCCodeChallenge) *oidc.CodeChallenge } } -func AMRFromMFAType(mfaType model.MFAType) string { +func AMRFromMFAType(mfaType domain.MFAType) string { switch mfaType { - case model.MFATypeOTP: + case domain.MFATypeOTP: return amrOTP - case model.MFATypeU2F, - model.MFATypeU2FUserVerification: + case domain.MFATypeU2F, + domain.MFATypeU2FUserVerification: return amrUserPresence default: return "" diff --git a/internal/api/oidc/op.go b/internal/api/oidc/op.go index f5a11012bf..de1ffa4f04 100644 --- a/internal/api/oidc/op.go +++ b/internal/api/oidc/op.go @@ -3,6 +3,8 @@ package oidc import ( "context" "github.com/caos/zitadel/internal/telemetry/metrics" + "github.com/caos/zitadel/internal/v2/command" + "github.com/caos/zitadel/internal/v2/query" "time" "github.com/caos/logging" @@ -46,13 +48,15 @@ type Endpoint struct { type OPStorage struct { repo repository.Repository + command *command.CommandSide + query *query.QuerySide defaultLoginURL string defaultAccessTokenLifetime time.Duration defaultIdTokenLifetime time.Duration signingKeyAlgorithm string } -func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Repository, localDevMode bool) op.OpenIDProvider { +func NewProvider(ctx context.Context, config OPHandlerConfig, command *command.CommandSide, query *query.QuerySide, repo repository.Repository, localDevMode bool) op.OpenIDProvider { cookieHandler, err := middleware.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator, localDevMode) logging.Log("OIDC-sd4fd").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Panic("cannot user agent handler") config.OPConfig.CodeMethodS256 = true @@ -60,7 +64,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re provider, err := op.NewOpenIDProvider( ctx, config.OPConfig, - newStorage(config.StorageConfig, repo), + newStorage(config.StorageConfig, command, query, repo), op.WithHttpInterceptors( middleware.MetricsHandler(metricTypes), middleware.TelemetryHandler(), @@ -79,9 +83,11 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re return provider } -func newStorage(config StorageConfig, repo repository.Repository) *OPStorage { +func newStorage(config StorageConfig, command *command.CommandSide, query *query.QuerySide, repo repository.Repository) *OPStorage { return &OPStorage{ repo: repo, + command: command, + query: query, defaultLoginURL: config.DefaultLoginURL, signingKeyAlgorithm: config.SigningKeyAlgorithm, defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime.Duration, diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go index 8425c68a06..1899c9f14a 100644 --- a/internal/auth/repository/auth_request.go +++ b/internal/auth/repository/auth_request.go @@ -2,32 +2,30 @@ package repository import ( "context" - "github.com/caos/zitadel/internal/auth_request/model" - org_model "github.com/caos/zitadel/internal/org/model" - user_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/v2/domain" ) type AuthRequestRepository interface { - CreateAuthRequest(ctx context.Context, request *model.AuthRequest) (*model.AuthRequest, error) - AuthRequestByID(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) - AuthRequestByIDCheckLoggedIn(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) - AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) + CreateAuthRequest(ctx context.Context, request *domain.AuthRequest) (*domain.AuthRequest, error) + AuthRequestByID(ctx context.Context, id, userAgentID string) (*domain.AuthRequest, error) + AuthRequestByIDCheckLoggedIn(ctx context.Context, id, userAgentID string) (*domain.AuthRequest, error) + AuthRequestByCode(ctx context.Context, code string) (*domain.AuthRequest, error) SaveAuthCode(ctx context.Context, id, code, userAgentID string) error DeleteAuthRequest(ctx context.Context, id string) error CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error - CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *model.ExternalUser, info *model.BrowserInfo) error + CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *domain.ExternalUser, info *domain.BrowserInfo) error SelectUser(ctx context.Context, id, userID, userAgentID string) error SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error - VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) error + VerifyPassword(ctx context.Context, id, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) error - VerifyMFAOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error - BeginMFAU2FLogin(ctx context.Context, userID, authRequestID, userAgentID string) (*user_model.WebAuthNLogin, error) - VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) error - BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (*user_model.WebAuthNLogin, error) - VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) error + VerifyMFAOTP(ctx context.Context, authRequestID, userID, resourceOwner, code, userAgentID string, info *domain.BrowserInfo) error + BeginMFAU2FLogin(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (*domain.WebAuthNLogin, error) + VerifyMFAU2F(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) error + BeginPasswordlessLogin(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (*domain.WebAuthNLogin, error) + VerifyPasswordless(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) error - LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) error - AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) error + LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *domain.BrowserInfo) error + AutoRegisterExternalUser(ctx context.Context, user *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, info *domain.BrowserInfo) error ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 92ef6aada6..3a3aba5092 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -2,6 +2,8 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/v2/command" + "github.com/caos/zitadel/internal/v2/domain" "time" "github.com/caos/logging" @@ -9,10 +11,10 @@ import ( "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/auth_request/model" + auth_req_model "github.com/caos/zitadel/internal/auth_request/model" cache "github.com/caos/zitadel/internal/auth_request/repository" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - "github.com/caos/zitadel/internal/eventstore/sdk" iam_model "github.com/caos/zitadel/internal/iam/model" iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" @@ -30,6 +32,7 @@ import ( ) type AuthRequestRepo struct { + Command *command.CommandSide UserEvents *user_event.UserEventstore OrgEvents *org_event.OrgEventstore AuthRequests cache.AuthRequestCache @@ -37,6 +40,7 @@ type AuthRequestRepo struct { UserSessionViewProvider userSessionViewProvider UserViewProvider userViewProvider + UserCommandProvider userCommandProvider UserEventProvider userEventProvider OrgViewProvider orgViewProvider LoginPolicyViewProvider loginPolicyViewProvider @@ -72,7 +76,10 @@ type idpProviderViewProvider interface { type userEventProvider interface { UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) - BulkAddExternalIDPs(ctx context.Context, userID string, externalIDPs []*user_model.ExternalIDP) error +} + +type userCommandProvider interface { + BulkAddedHumanExternalIDP(ctx context.Context, userID, resourceOwner string, externalIDPs []*domain.ExternalIDP) error } type orgViewProvider interface { @@ -92,7 +99,7 @@ func (repo *AuthRequestRepo) Health(ctx context.Context) error { return repo.AuthRequests.Health(ctx) } -func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *model.AuthRequest) (_ *model.AuthRequest, err error) { +func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *domain.AuthRequest) (_ *domain.AuthRequest, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() reqID, err := repo.IdGenerator.Next() @@ -124,13 +131,13 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod return request, nil } -func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id, userAgentID string) (_ *model.AuthRequest, err error) { +func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id, userAgentID string) (_ *domain.AuthRequest, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() return repo.getAuthRequestNextSteps(ctx, id, userAgentID, false) } -func (repo *AuthRequestRepo) AuthRequestByIDCheckLoggedIn(ctx context.Context, id, userAgentID string) (_ *model.AuthRequest, err error) { +func (repo *AuthRequestRepo) AuthRequestByIDCheckLoggedIn(ctx context.Context, id, userAgentID string) (_ *domain.AuthRequest, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() return repo.getAuthRequestNextSteps(ctx, id, userAgentID, true) @@ -147,7 +154,7 @@ func (repo *AuthRequestRepo) SaveAuthCode(ctx context.Context, id, code, userAge return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) (_ *model.AuthRequest, err error) { +func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) (_ *domain.AuthRequest, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.AuthRequests.GetAuthRequestByCode(ctx, code) @@ -200,7 +207,7 @@ func (repo *AuthRequestRepo) SelectExternalIDP(ctx context.Context, authReqID, i return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, externalUser *model.ExternalUser, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, externalUser *domain.ExternalUser, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) @@ -218,14 +225,14 @@ func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReq return err } - err = repo.UserEvents.ExternalLoginChecked(ctx, request.UserID, request.WithCurrentInfo(info)) + err = repo.Command.HumanExternalLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info)) if err != nil { return err } return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) setLinkingUser(ctx context.Context, request *model.AuthRequest, externalUser *model.ExternalUser) error { +func (repo *AuthRequestRepo) setLinkingUser(ctx context.Context, request *domain.AuthRequest, externalUser *domain.ExternalUser) error { request.LinkingUsers = append(request.LinkingUsers, externalUser) return repo.AuthRequests.UpdateAuthRequest(ctx, request) } @@ -248,27 +255,27 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequestEnsureUser(ctx, id, userAgentID, userID) if err != nil { return err } - return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info)) + return repo.Command.HumanCheckPassword(ctx, resourceOwner, userID, password, request.WithCurrentInfo(info)) } -func (repo *AuthRequestRepo) VerifyMFAOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) VerifyMFAOTP(ctx context.Context, authRequestID, userID, resourceOwner, code, userAgentID string, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) if err != nil { return err } - return repo.UserEvents.CheckMFAOTP(ctx, userID, code, request.WithCurrentInfo(info)) + return repo.Command.HumanCheckMFAOTP(ctx, userID, code, resourceOwner, request.WithCurrentInfo(info)) } -func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) { +func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (login *domain.WebAuthNLogin, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() @@ -276,51 +283,51 @@ func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authR if err != nil { return nil, err } - return repo.UserEvents.BeginU2FLogin(ctx, userID, request, true) + return repo.Command.HumanBeginU2FLogin(ctx, userID, resourceOwner, request, true) } -func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) if err != nil { return err } - return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request, true) + return repo.Command.HumanFinishU2FLogin(ctx, userID, resourceOwner, credentialData, request, true) } -func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) { +func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (login *domain.WebAuthNLogin, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) if err != nil { return nil, err } - return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request, true) + return repo.Command.HumanBeginPasswordlessLogin(ctx, userID, resourceOwner, request, true) } -func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) if err != nil { return err } - return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request, true) + return repo.Command.HumanFinishPasswordlessLogin(ctx, userID, resourceOwner, credentialData, request, true) } -func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) if err != nil { return err } - err = linkExternalIDPs(ctx, repo.UserEventProvider, request) + err = linkExternalIDPs(ctx, repo.UserCommandProvider, request) if err != nil { return err } - err = repo.UserEvents.ExternalLoginChecked(ctx, request.UserID, request.WithCurrentInfo(info)) + err = repo.Command.HumanExternalLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info)) if err != nil { return err } @@ -338,62 +345,29 @@ func (repo *AuthRequestRepo) ResetLinkingUsers(ctx context.Context, authReqID, u return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *user_model.User, externalIDP *user_model.ExternalIDP, orgMember *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) (err error) { +func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, info *domain.BrowserInfo) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) if err != nil { return err } - policyResourceOwner := authz.GetCtxData(ctx).OrgID - if resourceOwner != "" { - policyResourceOwner = resourceOwner - } - pwPolicy, err := repo.View.PasswordComplexityPolicyByAggregateID(policyResourceOwner) - if errors.IsNotFound(err) { - pwPolicy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.IAMID) - } + human, err := repo.Command.RegisterHuman(ctx, resourceOwner, registerUser, externalIDP, orgMemberRoles) if err != nil { return err } - pwPolicyView := iam_es_model.PasswordComplexityViewToModel(pwPolicy) - orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(policyResourceOwner) - if errors.IsNotFound(err) { - orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.IAMID) - } - if err != nil { - return err - } - orgPolicyView := iam_es_model.OrgIAMViewToModel(orgPolicy) - user, aggregates, err := repo.UserEvents.PrepareRegisterUser(ctx, registerUser, externalIDP, pwPolicyView, orgPolicyView, resourceOwner) - if err != nil { - return err - } - if orgMember != nil { - orgMember.UserID = user.AggregateID - _, memberAggregate, err := repo.OrgEvents.PrepareAddOrgMember(ctx, orgMember, policyResourceOwner) - if err != nil { - return err - } - aggregates = append(aggregates, memberAggregate) - } - - err = sdk.PushAggregates(ctx, repo.UserEvents.PushAggregates, user.AppendEvents, aggregates...) - if err != nil { - return err - } - request.UserID = user.AggregateID - request.UserOrgID = user.ResourceOwner + request.UserID = human.AggregateID + request.UserOrgID = human.ResourceOwner request.SelectedIDPConfigID = externalIDP.IDPConfigID request.LinkingUsers = nil - err = repo.UserEvents.ExternalLoginChecked(ctx, request.UserID, request.WithCurrentInfo(info)) + err = repo.Command.HumanExternalLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info)) if err != nil { return err } return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) getAuthRequestNextSteps(ctx context.Context, id, userAgentID string, checkLoggedIn bool) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) getAuthRequestNextSteps(ctx context.Context, id, userAgentID string, checkLoggedIn bool) (*domain.AuthRequest, error) { request, err := repo.getAuthRequest(ctx, id, userAgentID) if err != nil { return nil, err @@ -406,7 +380,7 @@ func (repo *AuthRequestRepo) getAuthRequestNextSteps(ctx context.Context, id, us return request, nil } -func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authRequestID, userAgentID, userID string) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authRequestID, userAgentID, userID string) (*domain.AuthRequest, error) { request, err := repo.getAuthRequest(ctx, authRequestID, userAgentID) if err != nil { return nil, err @@ -417,7 +391,7 @@ func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authR return request, nil } -func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID string) (*domain.AuthRequest, error) { request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) if err != nil { return nil, err @@ -432,22 +406,24 @@ func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID return request, nil } -func (repo *AuthRequestRepo) getLoginPolicyAndIDPProviders(ctx context.Context, orgID string) (*iam_model.LoginPolicyView, []*iam_model.IDPProviderView, error) { +func (repo *AuthRequestRepo) getLoginPolicyAndIDPProviders(ctx context.Context, orgID string) (*domain.LoginPolicy, []*domain.IDPProvider, error) { policy, err := repo.getLoginPolicy(ctx, orgID) if err != nil { return nil, nil, err } if !policy.AllowExternalIDP { - return policy, nil, nil + return policy.ToLoginPolicyDomain(), nil, nil } idpProviders, err := getLoginPolicyIDPProviders(repo.IDPProviderViewProvider, repo.IAMID, orgID, policy.Default) if err != nil { return nil, nil, err } - return policy, idpProviders, nil + + providers := iam_model.IdpProviderViewsToDomain(idpProviders) + return policy.ToLoginPolicyDomain(), providers, nil } -func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model.AuthRequest) error { +func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *domain.AuthRequest) error { orgID := request.RequestedOrgID if orgID == "" { orgID = request.UserOrgID @@ -467,7 +443,7 @@ func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model return nil } -func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.AuthRequest, loginName string) (err error) { +func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain.AuthRequest, loginName string) (err error) { user := new(user_view_model.UserView) if request.RequestedOrgID != "" { user, err = repo.View.UserByLoginNameAndResourceOwner(loginName, request.RequestedOrgID) @@ -488,7 +464,7 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model. return nil } -func (repo AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *model.AuthRequest, user *user_view_model.UserView) error { +func (repo AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *domain.AuthRequest, user *user_view_model.UserView) error { loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, user.ResourceOwner) if err != nil { return err @@ -507,7 +483,7 @@ func (repo AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Contex return nil } -func (repo *AuthRequestRepo) checkSelectedExternalIDP(request *model.AuthRequest, idpConfigID string) error { +func (repo *AuthRequestRepo) checkSelectedExternalIDP(request *domain.AuthRequest, idpConfigID string) error { for _, externalIDP := range request.AllowedExternalIDPs { if externalIDP.IDPConfigID == idpConfigID { request.SelectedIDPConfigID = idpConfigID @@ -517,7 +493,7 @@ func (repo *AuthRequestRepo) checkSelectedExternalIDP(request *model.AuthRequest return errors.ThrowNotFound(nil, "LOGIN-Nsm8r", "Errors.User.ExternalIDP.NotAllowed") } -func (repo *AuthRequestRepo) checkExternalUserLogin(request *model.AuthRequest, idpConfigID, externalUserID string) (err error) { +func (repo *AuthRequestRepo) checkExternalUserLogin(request *domain.AuthRequest, idpConfigID, externalUserID string) (err error) { externalIDP := new(user_view_model.ExternalIDPView) if request.RequestedOrgID != "" { externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, request.RequestedOrgID) @@ -531,27 +507,27 @@ func (repo *AuthRequestRepo) checkExternalUserLogin(request *model.AuthRequest, return nil } -func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthRequest, checkLoggedIn bool) ([]model.NextStep, error) { +func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.AuthRequest, checkLoggedIn bool) ([]domain.NextStep, error) { if request == nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "Errors.Internal") } - steps := make([]model.NextStep, 0) - if !checkLoggedIn && request.Prompt == model.PromptNone { - return append(steps, &model.RedirectToCallbackStep{}), nil + steps := make([]domain.NextStep, 0) + if !checkLoggedIn && request.Prompt == domain.PromptNone { + return append(steps, &domain.RedirectToCallbackStep{}), nil } if request.UserID == "" { if request.LinkingUsers != nil && len(request.LinkingUsers) > 0 { - steps = append(steps, new(model.ExternalNotFoundOptionStep)) + steps = append(steps, new(domain.ExternalNotFoundOptionStep)) return steps, nil } - steps = append(steps, new(model.LoginStep)) - if request.Prompt == model.PromptSelectAccount || request.Prompt == model.PromptUnspecified { + steps = append(steps, new(domain.LoginStep)) + if request.Prompt == domain.PromptSelectAccount || request.Prompt == domain.PromptUnspecified { users, err := repo.usersForUserSelection(request) if err != nil { return nil, err } - if len(users) > 0 || request.Prompt == model.PromptSelectAccount { - steps = append(steps, &model.SelectUserStep{Users: users}) + if len(users) > 0 || request.Prompt == domain.PromptSelectAccount { + steps = append(steps, &domain.SelectUserStep{Users: users}) } } return steps, nil @@ -572,7 +548,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR if selectedIDPConfigID == "" { selectedIDPConfigID = userSession.SelectedIDPConfigID } - return append(steps, &model.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil + return append(steps, &domain.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil } if isInternalLogin || (!isInternalLogin && len(request.LinkingUsers) > 0) { step := repo.firstFactorChecked(request, user, userSession) @@ -590,13 +566,13 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR } if user.PasswordChangeRequired { - steps = append(steps, &model.ChangePasswordStep{}) + steps = append(steps, &domain.ChangePasswordStep{}) } if !user.IsEmailVerified { - steps = append(steps, &model.VerifyEMailStep{}) + steps = append(steps, &domain.VerifyEMailStep{}) } if user.UsernameChangeRequired { - steps = append(steps, &model.ChangeUsernameStep{}) + steps = append(steps, &domain.ChangeUsernameStep{}) } if user.PasswordChangeRequired || !user.IsEmailVerified || user.UsernameChangeRequired { @@ -604,7 +580,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR } if request.LinkingUsers != nil && len(request.LinkingUsers) != 0 { - return append(steps, &model.LinkUsersStep{}), nil + return append(steps, &domain.LinkUsersStep{}), nil } //PLANNED: consent step @@ -614,46 +590,46 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR return nil, err } if missing { - return append(steps, &model.GrantRequiredStep{}), nil + return append(steps, &domain.GrantRequiredStep{}), nil } - return append(steps, &model.RedirectToCallbackStep{}), nil + return append(steps, &domain.RedirectToCallbackStep{}), nil } -func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) ([]model.UserSelection, error) { +func (repo *AuthRequestRepo) usersForUserSelection(request *domain.AuthRequest) ([]domain.UserSelection, error) { userSessions, err := userSessionsByUserAgentID(repo.UserSessionViewProvider, request.AgentID) if err != nil { return nil, err } - users := make([]model.UserSelection, len(userSessions)) + users := make([]domain.UserSelection, len(userSessions)) for i, session := range userSessions { - users[i] = model.UserSelection{ + users[i] = domain.UserSelection{ UserID: session.UserID, DisplayName: session.DisplayName, LoginName: session.LoginName, - UserSessionState: session.State, + UserSessionState: auth_req_model.UserSessionStateToDomain(session.State), SelectionPossible: request.RequestedOrgID == "" || request.RequestedOrgID == session.ResourceOwner, } } return users, nil } -func (repo *AuthRequestRepo) firstFactorChecked(request *model.AuthRequest, user *user_model.UserView, userSession *user_model.UserSessionView) model.NextStep { +func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, user *user_model.UserView, userSession *user_model.UserSessionView) domain.NextStep { if user.InitRequired { - return &model.InitUserStep{PasswordSet: user.PasswordSet} + return &domain.InitUserStep{PasswordSet: user.PasswordSet} } - var step model.NextStep - if request.LoginPolicy.PasswordlessType != iam_model.PasswordlessTypeNotAllowed && user.IsPasswordlessReady() { + var step domain.NextStep + if request.LoginPolicy.PasswordlessType != domain.PasswordlessTypeNotAllowed && user.IsPasswordlessReady() { if checkVerificationTime(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime) { request.AuthTime = userSession.PasswordlessVerification return nil } - step = &model.PasswordlessStep{} + step = &domain.PasswordlessStep{} } if !user.PasswordSet { - return &model.InitPasswordStep{} + return &domain.InitPasswordStep{} } if checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) { @@ -664,13 +640,13 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *model.AuthRequest, user if step != nil { return step } - return &model.PasswordStep{} + return &domain.PasswordStep{} } -func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) { +func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *domain.AuthRequest, user *user_model.UserView) (domain.NextStep, bool, error) { mfaLevel := request.MFALevel() allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy) - promptRequired := (user.MFAMaxSetUp < mfaLevel) || (len(allowedProviders) == 0 && required) + promptRequired := (auth_req_model.MFALevelToDomain(user.MFAMaxSetUp) < mfaLevel) || (len(allowedProviders) == 0 && required) if promptRequired || !repo.mfaSkippedOrSetUp(user) { types := user.MFATypesSetupPossible(mfaLevel, request.LoginPolicy) if promptRequired && len(types) == 0 { @@ -679,7 +655,7 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, if len(types) == 0 { return nil, true, nil } - return &model.MFAPromptStep{ + return &domain.MFAPromptStep{ Required: promptRequired, MFAProviders: types, }, false, nil @@ -687,26 +663,26 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, switch mfaLevel { default: fallthrough - case model.MFALevelNotSetUp: + case domain.MFALevelNotSetUp: if len(allowedProviders) == 0 { return nil, true, nil } fallthrough - case model.MFALevelSecondFactor: + case domain.MFALevelSecondFactor: if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) { - request.MFAsVerified = append(request.MFAsVerified, userSession.SecondFactorVerificationType) + request.MFAsVerified = append(request.MFAsVerified, auth_req_model.MFATypeToDomain(userSession.SecondFactorVerificationType)) request.AuthTime = userSession.SecondFactorVerification return nil, true, nil } fallthrough - case model.MFALevelMultiFactor: + case domain.MFALevelMultiFactor: if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) { - request.MFAsVerified = append(request.MFAsVerified, userSession.MultiFactorVerificationType) + request.MFAsVerified = append(request.MFAsVerified, auth_req_model.MFATypeToDomain(userSession.MultiFactorVerificationType)) request.AuthTime = userSession.MultiFactorVerification return nil, true, nil } } - return &model.MFAVerificationStep{ + return &domain.MFAVerificationStep{ MFAProviders: allowedProviders, }, false, nil } @@ -733,7 +709,7 @@ func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) ( return iam_es_model.LoginPolicyViewToModel(policy), err } -func setOrgID(orgViewProvider orgViewProvider, request *model.AuthRequest) error { +func setOrgID(orgViewProvider orgViewProvider, request *domain.AuthRequest) error { primaryDomain := request.GetScopeOrgPrimaryDomain() if primaryDomain == "" { return nil @@ -881,14 +857,14 @@ func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider return user_view_model.UserToModel(&userCopy), nil } -func linkExternalIDPs(ctx context.Context, userEventProvider userEventProvider, request *model.AuthRequest) error { - externalIDPs := make([]*user_model.ExternalIDP, len(request.LinkingUsers)) +func linkExternalIDPs(ctx context.Context, userCommandProvider userCommandProvider, request *domain.AuthRequest) error { + externalIDPs := make([]*domain.ExternalIDP, len(request.LinkingUsers)) for i, linkingUser := range request.LinkingUsers { - externalIDP := &user_model.ExternalIDP{ - ObjectRoot: es_models.ObjectRoot{AggregateID: request.UserID}, - IDPConfigID: linkingUser.IDPConfigID, - UserID: linkingUser.ExternalUserID, - DisplayName: linkingUser.DisplayName, + externalIDP := &domain.ExternalIDP{ + ObjectRoot: es_models.ObjectRoot{AggregateID: request.UserID}, + IDPConfigID: linkingUser.IDPConfigID, + ExternalUserID: linkingUser.ExternalUserID, + DisplayName: linkingUser.DisplayName, } externalIDPs[i] = externalIDP } @@ -896,10 +872,10 @@ func linkExternalIDPs(ctx context.Context, userEventProvider userEventProvider, UserID: "LOGIN", OrgID: request.UserOrgID, } - return userEventProvider.BulkAddExternalIDPs(authz.SetCtxData(ctx, data), request.UserID, externalIDPs) + return userCommandProvider.BulkAddedHumanExternalIDP(authz.SetCtxData(ctx, data), request.UserID, request.UserOrgID, externalIDPs) } -func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*model.ExternalUser, idpProviders []*iam_model.IDPProviderView) bool { +func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*domain.ExternalUser, idpProviders []*domain.IDPProvider) bool { for _, linkingUser := range linkingUsers { exists := false for _, idp := range idpProviders { @@ -914,10 +890,10 @@ func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*model.ExternalUser, i } return true } -func userGrantRequired(ctx context.Context, request *model.AuthRequest, user *user_model.UserView, userGrantProvider userGrantProvider) (_ bool, err error) { +func userGrantRequired(ctx context.Context, request *domain.AuthRequest, user *user_model.UserView, userGrantProvider userGrantProvider) (_ bool, err error) { var app *project_view_model.ApplicationView switch request.Request.Type() { - case model.AuthRequestTypeOIDC: + case domain.AuthRequestTypeOIDC: app, err = userGrantProvider.ApplicationByClientID(ctx, request.ApplicationID) if err != nil { return false, err diff --git a/internal/auth/repository/eventsourcing/eventstore/token.go b/internal/auth/repository/eventsourcing/eventstore/token.go index ec3e81aa7b..d71523c98a 100644 --- a/internal/auth/repository/eventsourcing/eventstore/token.go +++ b/internal/auth/repository/eventsourcing/eventstore/token.go @@ -2,12 +2,8 @@ package eventstore import ( "context" - "strings" - "github.com/caos/logging" - auth_req_model "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/telemetry/tracing" usr_model "github.com/caos/zitadel/internal/user/model" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" @@ -22,34 +18,6 @@ type TokenRepo struct { View *view.View } -func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, clientID, userID string, audience, scopes []string, lifetime time.Duration) (*usr_model.Token, error) { - preferredLanguage := "" - user, _ := repo.View.UserByID(userID) - if user != nil { - preferredLanguage = user.PreferredLanguage - } - - for _, scope := range scopes { - if strings.HasPrefix(scope, auth_req_model.ProjectIDScope) && strings.HasSuffix(scope, auth_req_model.AudSuffix) { - audience = append(audience, strings.TrimSuffix(strings.TrimPrefix(scope, auth_req_model.ProjectIDScope), auth_req_model.AudSuffix)) - } - } - - now := time.Now().UTC() - token := &usr_model.Token{ - ObjectRoot: models.ObjectRoot{ - AggregateID: userID, - }, - UserAgentID: agentID, - ApplicationID: clientID, - Audience: audience, - Scopes: scopes, - Expiration: now.Add(lifetime), - PreferredLanguage: preferredLanguage, - } - return repo.UserEvents.TokenAdded(ctx, token) -} - func (repo *TokenRepo) IsTokenValid(ctx context.Context, userID, tokenID string) (bool, error) { token, err := repo.TokenByID(ctx, userID, tokenID) if err == nil { diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go index 8c4a3e4e5d..b831f81865 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user.go +++ b/internal/auth/repository/eventsourcing/eventstore/user.go @@ -36,14 +36,6 @@ func (repo *UserRepo) Health(ctx context.Context) error { return repo.UserEvents.Health(ctx) } -func (repo *UserRepo) Register(ctx context.Context, user *model.User, orgMember *org_model.OrgMember, resourceOwner string) (*model.User, error) { - return repo.registerUser(ctx, user, nil, orgMember, resourceOwner) -} - -func (repo *UserRepo) RegisterExternalUser(ctx context.Context, user *model.User, externalIDP *model.ExternalIDP, orgMember *org_model.OrgMember, resourceOwner string) (*model.User, error) { - return repo.registerUser(ctx, user, externalIDP, orgMember, resourceOwner) -} - func (repo *UserRepo) registerUser(ctx context.Context, registerUser *model.User, externalIDP *model.ExternalIDP, orgMember *org_model.OrgMember, resourceOwner string) (*model.User, error) { policyResourceOwner := authz.GetCtxData(ctx).OrgID if resourceOwner != "" { @@ -133,18 +125,6 @@ func (repo *UserRepo) MyEmail(ctx context.Context) (*model.Email, error) { return user.GetEmail() } -func (repo *UserRepo) VerifyEmail(ctx context.Context, userID, code string) error { - return repo.UserEvents.VerifyEmail(ctx, userID, code) -} - -func (repo *UserRepo) VerifyMyEmail(ctx context.Context, code string) error { - return repo.UserEvents.VerifyEmail(ctx, authz.GetCtxData(ctx).UserID, code) -} - -func (repo *UserRepo) ResendEmailVerificationMail(ctx context.Context, userID string) error { - return repo.UserEvents.CreateEmailVerificationCode(ctx, userID) -} - func (repo *UserRepo) MyPhone(ctx context.Context) (*model.Phone, error) { user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID) if err != nil { @@ -156,21 +136,6 @@ func (repo *UserRepo) MyPhone(ctx context.Context) (*model.Phone, error) { return user.GetPhone() } -func (repo *UserRepo) ChangeMyPhone(ctx context.Context, phone *model.Phone) (*model.Phone, error) { - if err := checkIDs(ctx, phone.ObjectRoot); err != nil { - return nil, err - } - return repo.UserEvents.ChangePhone(ctx, phone) -} - -func (repo *UserRepo) RemoveMyPhone(ctx context.Context) error { - return repo.UserEvents.RemovePhone(ctx, authz.GetCtxData(ctx).UserID) -} - -func (repo *UserRepo) VerifyMyPhone(ctx context.Context, code string) error { - return repo.UserEvents.VerifyPhone(ctx, authz.GetCtxData(ctx).UserID, code) -} - func (repo *UserRepo) MyAddress(ctx context.Context) (*model.Address, error) { user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID) if err != nil { @@ -182,34 +147,6 @@ func (repo *UserRepo) MyAddress(ctx context.Context) (*model.Address, error) { return user.GetAddress() } -func (repo *UserRepo) ChangeMyPassword(ctx context.Context, old, new string) error { - policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if errors.IsNotFound(err) { - policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy) - _, err = repo.UserEvents.ChangePassword(ctx, pwPolicyView, authz.GetCtxData(ctx).UserID, old, new, "") - return err -} - -func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new, userAgentID string) (err error) { - ctx, span := tracing.NewSpan(ctx) - defer func() { span.EndWithError(err) }() - policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if errors.IsNotFound(err) { - policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy) - _, err = repo.UserEvents.ChangePassword(ctx, pwPolicyView, userID, old, new, userAgentID) - return err -} - func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, error) { user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID) if err != nil { @@ -225,142 +162,24 @@ func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, err return mfas, nil } -func (repo *UserRepo) AddMFAOTP(ctx context.Context, userID string) (*model.OTP, error) { - accountName := "" - user, err := repo.UserByID(ctx, userID) - if err != nil { - logging.Log("EVENT-Fk93s").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname") - } else { - accountName = user.PreferredLoginName - } - return repo.UserEvents.AddOTP(ctx, userID, accountName) -} - -func (repo *UserRepo) VerifyMFAOTPSetup(ctx context.Context, userID, code, userAgentID string) error { - return repo.UserEvents.CheckMFAOTPSetup(ctx, userID, code, userAgentID) -} - -func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error { - return repo.UserEvents.RemoveOTP(ctx, authz.GetCtxData(ctx).UserID) -} - -func (repo *UserRepo) AddMFAU2F(ctx context.Context, userID string) (*model.WebAuthNToken, error) { - accountName := "" - user, err := repo.UserByID(ctx, userID) - if err != nil { - logging.Log("EVENT-DAqe1").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname") - } else { - accountName = user.PreferredLoginName - } - return repo.UserEvents.AddU2F(ctx, userID, accountName, true) -} - -func (repo *UserRepo) AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) { - userID := authz.GetCtxData(ctx).UserID - accountName := "" - user, err := repo.UserByID(ctx, userID) - if err != nil { - logging.Log("EVENT-Ghwl1").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname") - } else { - accountName = user.PreferredLoginName - } - return repo.UserEvents.AddU2F(ctx, userID, accountName, false) -} - -func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error { - return repo.UserEvents.VerifyU2FSetup(ctx, userID, tokenName, userAgentID, credentialData) -} - func (repo *UserRepo) GetPasswordless(ctx context.Context, userID string) ([]*model.WebAuthNToken, error) { return repo.UserEvents.GetPasswordless(ctx, userID) } -func (repo *UserRepo) AddPasswordless(ctx context.Context, userID string) (*model.WebAuthNToken, error) { - accountName := "" - user, err := repo.UserByID(ctx, userID) - if err != nil { - logging.Log("EVENT-Vj2k1").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname") - } else { - accountName = user.PreferredLoginName - } - return repo.UserEvents.AddPasswordless(ctx, userID, accountName, true) -} - func (repo *UserRepo) GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNToken, error) { return repo.UserEvents.GetPasswordless(ctx, authz.GetCtxData(ctx).UserID) } -func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error { - return repo.UserEvents.VerifyPasswordlessSetup(ctx, userID, tokenName, userAgentID, credentialData) -} - -func (repo *UserRepo) RemoveMyPasswordless(ctx context.Context, webAuthNTokenID string) error { - return repo.UserEvents.RemovePasswordlessToken(ctx, authz.GetCtxData(ctx).UserID, webAuthNTokenID) -} - -func (repo *UserRepo) ChangeMyUsername(ctx context.Context, username string) error { - ctxData := authz.GetCtxData(ctx) - orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(ctxData.OrgID) - if errors.IsNotFound(err) { - orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - orgPolicyView := iam_es_model.OrgIAMViewToModel(orgPolicy) - return repo.UserEvents.ChangeUsername(ctx, ctxData.UserID, username, orgPolicyView) -} -func (repo *UserRepo) ResendInitVerificationMail(ctx context.Context, userID string) error { - _, err := repo.UserEvents.CreateInitializeUserCodeByID(ctx, userID) - return err -} - -func (repo *UserRepo) VerifyInitCode(ctx context.Context, userID, code, password string) error { - policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if errors.IsNotFound(err) { - policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy) - return repo.UserEvents.VerifyInitCode(ctx, pwPolicyView, userID, code, password) -} - -func (repo *UserRepo) SkipMFAInit(ctx context.Context, userID string) error { - return repo.UserEvents.SkipMFAInit(ctx, userID) -} - -func (repo *UserRepo) RequestPasswordReset(ctx context.Context, loginname string) error { - user, err := repo.View.UserByLoginName(loginname) - if err != nil { - return err - } - return repo.UserEvents.RequestSetPassword(ctx, user.ID, model.NotificationTypeEmail) -} - -func (repo *UserRepo) SetPassword(ctx context.Context, userID, code, password, userAgentID string) error { - policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if errors.IsNotFound(err) { - policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy) - return repo.UserEvents.SetPassword(ctx, pwPolicyView, userID, code, password, userAgentID) -} - -func (repo *UserRepo) SignOut(ctx context.Context, agentID string) error { +func (repo *UserRepo) UserSessionUserIDsByAgentID(ctx context.Context, agentID string) ([]string, error) { userSessions, err := repo.View.UserSessionsByAgentID(agentID) if err != nil { - return err + return nil, err } userIDs := make([]string, len(userSessions)) for i, session := range userSessions { userIDs[i] = session.UserID } - return repo.UserEvents.SignOut(ctx, agentID, userIDs) + return userIDs, nil } func (repo *UserRepo) UserByID(ctx context.Context, id string) (*model.UserView, error) { @@ -385,6 +204,27 @@ func (repo *UserRepo) UserByID(ctx context.Context, id string) (*model.UserView, return usr_view_model.UserToModel(&userCopy), nil } +func (repo *UserRepo) UserByLoginName(ctx context.Context, loginname string) (*model.UserView, error) { + user, err := repo.View.UserByLoginName(loginname) + if err != nil { + return nil, err + } + events, err := repo.UserEvents.UserEventsByID(ctx, user.ID, user.Sequence) + if err != nil { + logging.Log("EVENT-PSoc3").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("error retrieving new events") + return usr_view_model.UserToModel(user), nil + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return usr_view_model.UserToModel(user), nil + } + } + if userCopy.State == int32(model.UserStateDeleted) { + return nil, errors.ThrowNotFound(nil, "EVENT-vZ8us", "Errors.User.NotFound") + } + return usr_view_model.UserToModel(&userCopy), nil +} func (repo *UserRepo) MyUserChanges(ctx context.Context, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) { changes, err := repo.UserEvents.UserChanges(ctx, authz.GetCtxData(ctx).UserID, lastSequence, limit, sortAscending) if err != nil { @@ -405,19 +245,6 @@ func (repo *UserRepo) MyUserChanges(ctx context.Context, lastSequence uint64, li return changes, nil } -func (repo *UserRepo) ChangeUsername(ctx context.Context, userID, username string) error { - policyResourceOwner := authz.GetCtxData(ctx).OrgID - orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(policyResourceOwner) - if errors.IsNotFound(err) { - orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - orgPolicyView := iam_es_model.OrgIAMViewToModel(orgPolicy) - return repo.UserEvents.ChangeUsername(ctx, userID, username, orgPolicyView) -} - func checkIDs(ctx context.Context, obj es_models.ObjectRoot) error { if obj.AggregateID != authz.GetCtxData(ctx).UserID { return errors.ThrowPermissionDenied(nil, "EVENT-kFi9w", "object does not belong to user") diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index 3d196ee067..e554e06602 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -20,6 +20,7 @@ import ( es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_user "github.com/caos/zitadel/internal/user/repository/eventsourcing" + "github.com/caos/zitadel/internal/v2/command" "github.com/caos/zitadel/internal/v2/query" ) @@ -46,7 +47,7 @@ type EsRepository struct { eventstore.IAMRepository } -func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, authZRepo *authz_repo.EsRepository) (*EsRepository, error) { +func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, command *command.CommandSide, authZRepo *authz_repo.EsRepository) (*EsRepository, error) { es, err := es_int.Start(conf.Eventstore) if err != nil { return nil, err @@ -131,12 +132,14 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au SystemDefaults: systemDefaults, }, eventstore.AuthRequestRepo{ + Command: command, UserEvents: user, OrgEvents: org, AuthRequests: authReq, View: view, UserSessionViewProvider: view, UserViewProvider: view, + UserCommandProvider: command, UserEventProvider: user, OrgViewProvider: view, IDPProviderViewProvider: view, diff --git a/internal/auth/repository/token.go b/internal/auth/repository/token.go index c5d5130593..1451e06aea 100644 --- a/internal/auth/repository/token.go +++ b/internal/auth/repository/token.go @@ -3,11 +3,9 @@ package repository import ( "context" usr_model "github.com/caos/zitadel/internal/user/model" - "time" ) type TokenRepository interface { - CreateToken(ctx context.Context, agentID, clientID, userID string, audience, scopes []string, lifetime time.Duration) (*usr_model.Token, error) IsTokenValid(ctx context.Context, userID, tokenID string) (bool, error) TokenByID(ctx context.Context, userID, tokenID string) (*usr_model.TokenView, error) } diff --git a/internal/auth/repository/user.go b/internal/auth/repository/user.go index d1eb3257b7..46a93c13f1 100644 --- a/internal/auth/repository/user.go +++ b/internal/auth/repository/user.go @@ -3,43 +3,18 @@ package repository import ( "context" - org_model "github.com/caos/zitadel/internal/org/model" - "github.com/caos/zitadel/internal/user/model" ) type UserRepository interface { - Register(ctx context.Context, user *model.User, member *org_model.OrgMember, resourceOwner string) (*model.User, error) - RegisterExternalUser(ctx context.Context, user *model.User, externalIDP *model.ExternalIDP, member *org_model.OrgMember, resourceOwner string) (*model.User, error) - myUserRepo - SkipMFAInit(ctx context.Context, userID string) error - - RequestPasswordReset(ctx context.Context, username string) error - SetPassword(ctx context.Context, userID, code, password, userAgentID string) error - ChangePassword(ctx context.Context, userID, old, new, userAgentID string) error - - VerifyEmail(ctx context.Context, userID, code string) error - ResendEmailVerificationMail(ctx context.Context, userID string) error - - VerifyInitCode(ctx context.Context, userID, code, password string) error - ResendInitVerificationMail(ctx context.Context, userID string) error - - AddMFAOTP(ctx context.Context, userID string) (*model.OTP, error) - VerifyMFAOTPSetup(ctx context.Context, userID, code, userAgentID string) error - - AddMFAU2F(ctx context.Context, id string) (*model.WebAuthNToken, error) - VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error GetPasswordless(ctx context.Context, id string) ([]*model.WebAuthNToken, error) - AddPasswordless(ctx context.Context, id string) (*model.WebAuthNToken, error) - VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error - ChangeUsername(ctx context.Context, userID, username string) error - - SignOut(ctx context.Context, agentID string) error + UserSessionUserIDsByAgentID(ctx context.Context, agentID string) ([]string, error) UserByID(ctx context.Context, userID string) (*model.UserView, error) + UserByLoginName(ctx context.Context, loginName string) (*model.UserView, error) MachineKeyByID(ctx context.Context, keyID string) (*model.MachineKeyView, error) } @@ -59,8 +34,6 @@ type myUserRepo interface { MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, error) - AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) - GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNToken, error) MyUserChanges(ctx context.Context, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) diff --git a/internal/auth_request/model/next_step.go b/internal/auth_request/model/next_step.go index b3a3a07733..3d4a5e01ec 100644 --- a/internal/auth_request/model/next_step.go +++ b/internal/auth_request/model/next_step.go @@ -1,5 +1,9 @@ package model +import ( + "github.com/caos/zitadel/internal/v2/domain" +) + type NextStep interface { Type() NextStepType } @@ -164,3 +168,45 @@ const ( MFALevelMultiFactor MFALevelMultiFactorCertified ) + +func MFATypeToDomain(mfaType MFAType) domain.MFAType { + switch mfaType { + case MFATypeOTP: + return domain.MFATypeOTP + case MFATypeU2F: + return domain.MFATypeU2F + case MFATypeU2FUserVerification: + return domain.MFATypeU2FUserVerification + default: + return domain.MFATypeOTP + } + +} + +func MFALevelToDomain(mfaLevel MFALevel) domain.MFALevel { + switch mfaLevel { + case MFALevelNotSetUp: + return domain.MFALevelNotSetUp + case MFALevelSecondFactor: + return domain.MFALevelSecondFactor + case MFALevelMultiFactor: + return domain.MFALevelMultiFactor + case MFALevelMultiFactorCertified: + return domain.MFALevelMultiFactorCertified + default: + return domain.MFALevelNotSetUp + } + +} + +func UserSessionStateToDomain(state UserSessionState) domain.UserSessionState { + switch state { + case UserSessionStateActive: + return domain.UserSessionStateActive + case UserSessionStateTerminated: + return domain.UserSessionStateTerminated + default: + return domain.UserSessionStateActive + } + +} diff --git a/internal/auth_request/repository/cache/cache.go b/internal/auth_request/repository/cache/cache.go index 1a85c6eb5d..7bfacaaf5d 100644 --- a/internal/auth_request/repository/cache/cache.go +++ b/internal/auth_request/repository/cache/cache.go @@ -6,8 +6,8 @@ import ( "encoding/json" "errors" "fmt" + "github.com/caos/zitadel/internal/v2/domain" - "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/config/types" caos_errs "github.com/caos/zitadel/internal/errors" ) @@ -34,19 +34,19 @@ func (c *AuthRequestCache) Health(ctx context.Context) error { return c.client.PingContext(ctx) } -func (c *AuthRequestCache) GetAuthRequestByID(_ context.Context, id string) (*model.AuthRequest, error) { +func (c *AuthRequestCache) GetAuthRequestByID(_ context.Context, id string) (*domain.AuthRequest, error) { return c.getAuthRequest("id", id) } -func (c *AuthRequestCache) GetAuthRequestByCode(_ context.Context, code string) (*model.AuthRequest, error) { +func (c *AuthRequestCache) GetAuthRequestByCode(_ context.Context, code string) (*domain.AuthRequest, error) { return c.getAuthRequest("code", code) } -func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *model.AuthRequest) error { +func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *domain.AuthRequest) error { return c.saveAuthRequest(request, "INSERT INTO auth.auth_requests (id, request, request_type) VALUES($1, $2, $3)", request.Request.Type()) } -func (c *AuthRequestCache) UpdateAuthRequest(_ context.Context, request *model.AuthRequest) error { +func (c *AuthRequestCache) UpdateAuthRequest(_ context.Context, request *domain.AuthRequest) error { return c.saveAuthRequest(request, "UPDATE auth.auth_requests SET request = $2, code = $3 WHERE id = $1", request.Code) } @@ -58,9 +58,9 @@ func (c *AuthRequestCache) DeleteAuthRequest(_ context.Context, id string) error return nil } -func (c *AuthRequestCache) getAuthRequest(key, value string) (*model.AuthRequest, error) { +func (c *AuthRequestCache) getAuthRequest(key, value string) (*domain.AuthRequest, error) { var b []byte - var requestType model.AuthRequestType + var requestType domain.AuthRequestType query := fmt.Sprintf("SELECT request, request_type FROM auth.auth_requests WHERE %s = $1", key) err := c.client.QueryRow(query, value).Scan(&b, &requestType) if err != nil { @@ -69,7 +69,7 @@ func (c *AuthRequestCache) getAuthRequest(key, value string) (*model.AuthRequest } return nil, caos_errs.ThrowInternal(err, "CACHE-as3kj", "Errors.Internal") } - request, err := model.NewAuthRequestFromType(requestType) + request, err := domain.NewAuthRequestFromType(requestType) if err == nil { err = json.Unmarshal(b, request) } @@ -79,7 +79,7 @@ func (c *AuthRequestCache) getAuthRequest(key, value string) (*model.AuthRequest return request, nil } -func (c *AuthRequestCache) saveAuthRequest(request *model.AuthRequest, query string, param interface{}) error { +func (c *AuthRequestCache) saveAuthRequest(request *domain.AuthRequest, query string, param interface{}) error { b, err := json.Marshal(request) if err != nil { return caos_errs.ThrowInternal(err, "CACHE-os0GH", "Errors.Internal") diff --git a/internal/auth_request/repository/mock/repository.mock.go b/internal/auth_request/repository/mock/repository.mock.go index 9d23f6e35f..95433e4610 100644 --- a/internal/auth_request/repository/mock/repository.mock.go +++ b/internal/auth_request/repository/mock/repository.mock.go @@ -107,7 +107,7 @@ func (mr *MockAuthRequestCacheMockRecorder) SaveAuthRequest(arg0, arg1 interface } // UpdateAuthRequest mocks base method -func (m *MockAuthRequestCache) UpdateAuthRequest(arg0 context.Context, arg1 *model.AuthRequest) error { +func (m *MockAuthRequestCache) UpdateAuthRequest(arg0 context.Context, arg1 *domain.AuthRequest) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateAuthRequest", arg0, arg1) ret0, _ := ret[0].(error) diff --git a/internal/auth_request/repository/repository.go b/internal/auth_request/repository/repository.go index f72d2c8fda..ab9ca86f47 100644 --- a/internal/auth_request/repository/repository.go +++ b/internal/auth_request/repository/repository.go @@ -2,16 +2,15 @@ package repository import ( "context" - - "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/v2/domain" ) type AuthRequestCache interface { Health(ctx context.Context) error - GetAuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) - GetAuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) - SaveAuthRequest(ctx context.Context, request *model.AuthRequest) error - UpdateAuthRequest(ctx context.Context, request *model.AuthRequest) error + GetAuthRequestByID(ctx context.Context, id string) (*domain.AuthRequest, error) + GetAuthRequestByCode(ctx context.Context, code string) (*domain.AuthRequest, error) + SaveAuthRequest(ctx context.Context, request *domain.AuthRequest) error + UpdateAuthRequest(ctx context.Context, request *domain.AuthRequest) error DeleteAuthRequest(ctx context.Context, id string) error } diff --git a/internal/eventstore/v2/eventstore_test.go b/internal/eventstore/v2/eventstore_test.go index a841f99e77..81a2de1c2a 100644 --- a/internal/eventstore/v2/eventstore_test.go +++ b/internal/eventstore/v2/eventstore_test.go @@ -63,7 +63,7 @@ func (e *testEvent) Data() interface{} { return e.data() } -func (e *testEvent) UniqueConstraint() []EventUniqueConstraint { +func (e *testEvent) UniqueConstraint() []*EventUniqueConstraint { return nil } diff --git a/internal/eventstore/v2/repository/sql/crdb.go b/internal/eventstore/v2/repository/sql/crdb.go index 7b65f616a9..e9ad16a231 100644 --- a/internal/eventstore/v2/repository/sql/crdb.go +++ b/internal/eventstore/v2/repository/sql/crdb.go @@ -188,7 +188,7 @@ func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueC logging.LogWithFields("SQL-M0vsf", "unique_type", uniqueConstraint.UniqueType, "unique_field", uniqueConstraint.UniqueField).WithError(err).Info("delete unique constraint failed") - return caos_errs.ThrowInternal(err, "SQL-2M9fs", "unable to remove unique constraint ") + return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraint ") } } } diff --git a/internal/eventstore/v2/search_query.go b/internal/eventstore/v2/search_query.go index 64961e8e7f..634b2ccccc 100644 --- a/internal/eventstore/v2/search_query.go +++ b/internal/eventstore/v2/search_query.go @@ -139,14 +139,22 @@ func (factory *SearchQueryBuilder) eventTypeFilter() *repository.Filter { if len(factory.eventTypes) == 1 { return repository.NewFilter(repository.FieldEventType, factory.eventTypes[0], repository.OperationEquals) } - return repository.NewFilter(repository.FieldEventType, factory.eventTypes, repository.OperationIn) + eventTypes := make([]repository.EventType, len(factory.eventTypes)) + for i, eventType := range factory.eventTypes { + eventTypes[i] = repository.EventType(eventType) + } + return repository.NewFilter(repository.FieldEventType, eventTypes, repository.OperationIn) } func (factory *SearchQueryBuilder) aggregateTypeFilter() *repository.Filter { if len(factory.aggregateTypes) == 1 { return repository.NewFilter(repository.FieldAggregateType, factory.aggregateTypes[0], repository.OperationEquals) } - return repository.NewFilter(repository.FieldAggregateType, factory.aggregateTypes, repository.OperationIn) + aggregateTypes := make([]repository.AggregateType, len(factory.aggregateTypes)) + for i, aggregateType := range factory.aggregateTypes { + aggregateTypes[i] = repository.AggregateType(aggregateType) + } + return repository.NewFilter(repository.FieldAggregateType, aggregateTypes, repository.OperationIn) } func (factory *SearchQueryBuilder) eventSequenceFilter() *repository.Filter { diff --git a/internal/iam/model/idp_provider_view.go b/internal/iam/model/idp_provider_view.go index 5a8f981c13..0ac112147e 100644 --- a/internal/iam/model/idp_provider_view.go +++ b/internal/iam/model/idp_provider_view.go @@ -2,6 +2,7 @@ package model import ( "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/v2/domain" "time" ) @@ -60,3 +61,63 @@ func (r *IDPProviderSearchRequest) EnsureLimit(limit uint64) { func (r *IDPProviderSearchRequest) AppendAggregateIDQuery(aggregateID string) { r.Queries = append(r.Queries, &IDPProviderSearchQuery{Key: IDPProviderSearchKeyAggregateID, Method: model.SearchMethodEquals, Value: aggregateID}) } + +func IdpProviderViewsToDomain(idpProviders []*IDPProviderView) []*domain.IDPProvider { + providers := make([]*domain.IDPProvider, len(idpProviders)) + for i, provider := range idpProviders { + p := &domain.IDPProvider{ + IDPConfigID: provider.IDPConfigID, + Type: idpProviderTypeToDomain(provider.IDPProviderType), + Name: provider.Name, + IDPConfigType: idpConfigTypeToDomain(provider.IDPConfigType), + StylingType: idpStylingTypeToDomain(provider.StylingType), + IDPState: idpStateToDomain(provider.IDPState), + } + providers[i] = p + } + return providers +} + +func idpProviderTypeToDomain(idpType IDPProviderType) domain.IdentityProviderType { + switch idpType { + case IDPProviderTypeSystem: + return domain.IdentityProviderTypeSystem + case IDPProviderTypeOrg: + return domain.IdentityProviderTypeOrg + default: + return domain.IdentityProviderTypeSystem + } +} + +func idpConfigTypeToDomain(idpType IdpConfigType) domain.IDPConfigType { + switch idpType { + case IDPConfigTypeOIDC: + return domain.IDPConfigTypeOIDC + case IDPConfigTypeSAML: + return domain.IDPConfigTypeSAML + default: + return domain.IDPConfigTypeOIDC + } +} + +func idpStylingTypeToDomain(stylingType IDPStylingType) domain.IDPConfigStylingType { + switch stylingType { + case IDPStylingTypeGoogle: + return domain.IDPConfigStylingTypeGoogle + default: + return domain.IDPConfigStylingTypeUnspecified + } +} + +func idpStateToDomain(state IDPConfigState) domain.IDPConfigState { + switch state { + case IDPConfigStateActive: + return domain.IDPConfigStateActive + case IDPConfigStateInactive: + return domain.IDPConfigStateInactive + case IDPConfigStateRemoved: + return domain.IDPConfigStateRemoved + default: + return domain.IDPConfigStateActive + } +} diff --git a/internal/iam/model/login_policy_view.go b/internal/iam/model/login_policy_view.go index 4bc6d51850..b28a3f62e2 100644 --- a/internal/iam/model/login_policy_view.go +++ b/internal/iam/model/login_policy_view.go @@ -1,7 +1,9 @@ package model import ( + "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/v2/domain" "time" ) @@ -64,3 +66,57 @@ func (p *LoginPolicyView) HasMultiFactors() bool { } return true } + +func (p *LoginPolicyView) ToLoginPolicyDomain() *domain.LoginPolicy { + return &domain.LoginPolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: p.AggregateID, + CreationDate: p.CreationDate, + ChangeDate: p.ChangeDate, + Sequence: p.Sequence, + }, + Default: p.Default, + AllowUsernamePassword: p.AllowUsernamePassword, + AllowRegister: p.AllowRegister, + AllowExternalIDP: p.AllowExternalIDP, + ForceMFA: p.ForceMFA, + PasswordlessType: passwordLessTypeToDomain(p.PasswordlessType), + SecondFactors: secondFactorsToDomain(p.SecondFactors), + MultiFactors: multiFactorsToDomain(p.MultiFactors), + } +} + +func passwordLessTypeToDomain(passwordless PasswordlessType) domain.PasswordlessType { + switch passwordless { + case PasswordlessTypeNotAllowed: + return domain.PasswordlessTypeNotAllowed + case PasswordlessTypeAllowed: + return domain.PasswordlessTypeAllowed + default: + return domain.PasswordlessTypeNotAllowed + } +} + +func secondFactorsToDomain(types []SecondFactorType) []domain.SecondFactorType { + secondfactors := make([]domain.SecondFactorType, len(types)) + for i, secondfactorType := range types { + switch secondfactorType { + case SecondFactorTypeU2F: + secondfactors[i] = domain.SecondFactorTypeU2F + case SecondFactorTypeOTP: + secondfactors[i] = domain.SecondFactorTypeOTP + } + } + return secondfactors +} + +func multiFactorsToDomain(types []MultiFactorType) []domain.MultiFactorType { + multifactors := make([]domain.MultiFactorType, len(types)) + for i, multifactorType := range types { + switch multifactorType { + case MultiFactorTypeU2FWithPIN: + multifactors[i] = domain.MultiFactorTypeU2FWithPIN + } + } + return multifactors +} diff --git a/internal/management/repository/eventsourcing/eventstore/user.go b/internal/management/repository/eventsourcing/eventstore/user.go index aa860d1bdd..b586d87504 100644 --- a/internal/management/repository/eventsourcing/eventstore/user.go +++ b/internal/management/repository/eventsourcing/eventstore/user.go @@ -9,7 +9,6 @@ import ( "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors" es_int "github.com/caos/zitadel/internal/eventstore" - iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" global_model "github.com/caos/zitadel/internal/model" org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" @@ -194,26 +193,6 @@ func (repo *UserRepo) SearchMachineKeys(ctx context.Context, request *usr_model. return result, nil } -func (repo *UserRepo) AddMachineKey(ctx context.Context, key *usr_model.MachineKey) (*usr_model.MachineKey, error) { - return repo.UserEvents.AddMachineKey(ctx, key) -} - -func (repo *UserRepo) RemoveMachineKey(ctx context.Context, userID, keyID string) error { - return repo.UserEvents.RemoveMachineKey(ctx, userID, keyID) -} - -func (repo *UserRepo) ChangeUsername(ctx context.Context, userID, userName string) error { - orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) - if err != nil && errors.IsNotFound(err) { - orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID) - } - if err != nil { - return err - } - orgPolicyView := iam_es_model.OrgIAMViewToModel(orgPolicy) - return repo.UserEvents.ChangeUsername(ctx, userID, userName, orgPolicyView) -} - func (repo *UserRepo) EmailByID(ctx context.Context, userID string) (*usr_model.Email, error) { user, err := repo.UserByID(ctx, userID) if err != nil { diff --git a/internal/management/repository/eventsourcing/eventstore/user_grant.go b/internal/management/repository/eventsourcing/eventstore/user_grant.go index bf49bebe3c..e79e325e6a 100644 --- a/internal/management/repository/eventsourcing/eventstore/user_grant.go +++ b/internal/management/repository/eventsourcing/eventstore/user_grant.go @@ -27,6 +27,22 @@ func (repo *UserGrantRepo) UserGrantByID(ctx context.Context, grantID string) (* return model.UserGrantToModel(grant), nil } +func (repo *UserGrantRepo) UserGrantsByProjectID(ctx context.Context, projectID string) ([]*grant_model.UserGrantView, error) { + grants, err := repo.View.UserGrantsByProjectID(projectID) + if err != nil { + return nil, err + } + return model.UserGrantsToModel(grants), nil +} + +func (repo *UserGrantRepo) UserGrantsByUserID(ctx context.Context, userID string) ([]*grant_model.UserGrantView, error) { + grants, err := repo.View.UserGrantsByUserID(userID) + if err != nil { + return nil, err + } + return model.UserGrantsToModel(grants), nil +} + func (repo *UserGrantRepo) SearchUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) { request.EnsureLimit(repo.SearchLimit) sequence, sequenceErr := repo.View.GetLatestUserGrantSequence("") diff --git a/internal/management/repository/user.go b/internal/management/repository/user.go index b1d19e6332..b545ecb6d1 100644 --- a/internal/management/repository/user.go +++ b/internal/management/repository/user.go @@ -25,8 +25,6 @@ type UserRepository interface { SearchMachineKeys(ctx context.Context, request *model.MachineKeySearchRequest) (*model.MachineKeySearchResponse, error) GetMachineKey(ctx context.Context, userID, keyID string) (*model.MachineKeyView, error) - AddMachineKey(ctx context.Context, key *model.MachineKey) (*model.MachineKey, error) - RemoveMachineKey(ctx context.Context, userID, keyID string) error EmailByID(ctx context.Context, userID string) (*model.Email, error) diff --git a/internal/management/repository/user_grant.go b/internal/management/repository/user_grant.go index 18b7b179d3..00714568a1 100644 --- a/internal/management/repository/user_grant.go +++ b/internal/management/repository/user_grant.go @@ -8,4 +8,6 @@ import ( type UserGrantRepository interface { UserGrantByID(ctx context.Context, grantID string) (*model.UserGrantView, error) SearchUserGrants(ctx context.Context, request *model.UserGrantSearchRequest) (*model.UserGrantSearchResponse, error) + UserGrantsByProjectID(ctx context.Context, projectID string) ([]*model.UserGrantView, error) + UserGrantsByUserID(ctx context.Context, userID string) ([]*model.UserGrantView, error) } diff --git a/internal/notification/notification.go b/internal/notification/notification.go index 631df76eeb..3fe5a8c947 100644 --- a/internal/notification/notification.go +++ b/internal/notification/notification.go @@ -5,6 +5,7 @@ import ( "github.com/caos/logging" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/notification/repository/eventsourcing" + "github.com/caos/zitadel/internal/v2/command" "github.com/rakyll/statik/fs" _ "github.com/caos/zitadel/internal/notification/statik" @@ -14,10 +15,10 @@ type Config struct { Repository eventsourcing.Config } -func Start(ctx context.Context, config Config, systemDefaults sd.SystemDefaults) { +func Start(ctx context.Context, config Config, systemDefaults sd.SystemDefaults, command *command.CommandSide) { statikFS, err := fs.NewWithNamespace("notification") logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start listener") - _, err = eventsourcing.Start(config.Repository, statikFS, systemDefaults) + _, err = eventsourcing.Start(config.Repository, statikFS, systemDefaults, command) logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") } diff --git a/internal/notification/repository/eventsourcing/handler/handler.go b/internal/notification/repository/eventsourcing/handler/handler.go index eb8035ed88..ef91b94256 100644 --- a/internal/notification/repository/eventsourcing/handler/handler.go +++ b/internal/notification/repository/eventsourcing/handler/handler.go @@ -1,6 +1,7 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/command" "net/http" "time" @@ -42,7 +43,7 @@ type EventstoreRepos struct { IAMEvents *iam_es.IAMEventstore } -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, command *command.CommandSide, repos EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler { aesCrypto, err := crypto.NewAESCrypto(systemDefaults.UserVerificationKey) if err != nil { logging.Log("HANDL-s90ew").WithError(err).Debug("error create new aes crypto") @@ -56,6 +57,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es ), newNotification( handler{view, bulkLimit, configs.cycleDuration("Notification"), errorCount, es}, + command, repos.UserEvents, systemDefaults, aesCrypto, diff --git a/internal/notification/repository/eventsourcing/handler/notification.go b/internal/notification/repository/eventsourcing/handler/notification.go index 0d37914e3a..ac22f914cf 100644 --- a/internal/notification/repository/eventsourcing/handler/notification.go +++ b/internal/notification/repository/eventsourcing/handler/notification.go @@ -3,6 +3,8 @@ package handler import ( "context" "encoding/json" + "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/v2/command" "net/http" "time" @@ -32,6 +34,7 @@ const ( type Notification struct { handler + command *command.CommandSide userEvents *usr_event.UserEventstore systemDefaults sd.SystemDefaults AesCrypto crypto.EncryptionAlgorithm @@ -42,6 +45,7 @@ type Notification struct { func newNotification( handler handler, + command *command.CommandSide, userEvents *usr_event.UserEventstore, defaults sd.SystemDefaults, aesCrypto crypto.EncryptionAlgorithm, @@ -50,6 +54,7 @@ func newNotification( ) *Notification { h := &Notification{ handler: handler, + command: command, userEvents: userEvents, systemDefaults: defaults, i18n: translator, @@ -135,7 +140,7 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) { return err } - user, err := n.view.NotifyUserByID(event.AggregateID) + user, err := n.getUserByID(event.AggregateID) if err != nil { return err } @@ -143,7 +148,7 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) { if err != nil { return err } - return n.userEvents.InitCodeSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID) + return n.command.HumanInitCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID) } func (n *Notification) handlePasswordCode(event *models.Event) (err error) { @@ -163,7 +168,7 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) { return err } - user, err := n.view.NotifyUserByID(event.AggregateID) + user, err := n.getUserByID(event.AggregateID) if err != nil { return err } @@ -171,7 +176,7 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) { if err != nil { return err } - return n.userEvents.PasswordCodeSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID) + return n.command.PasswordCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID) } func (n *Notification) handleEmailVerificationCode(event *models.Event) (err error) { @@ -191,7 +196,7 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err return err } - user, err := n.view.NotifyUserByID(event.AggregateID) + user, err := n.getUserByID(event.AggregateID) if err != nil { return err } @@ -199,7 +204,7 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err if err != nil { return err } - return n.userEvents.EmailVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID) + return n.command.HumanEmailVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID) } func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err error) { @@ -213,7 +218,7 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err if err != nil || alreadyHandled { return nil } - user, err := n.view.NotifyUserByID(event.AggregateID) + user, err := n.getUserByID(event.AggregateID) if err != nil { return err } @@ -221,7 +226,7 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err if err != nil { return err } - return n.userEvents.PhoneVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID) + return n.command.HumanPhoneVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID) } func (n *Notification) handleDomainClaimed(event *models.Event) (err error) { @@ -234,7 +239,7 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) { logging.Log("HANDLE-Gghq2").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "HANDLE-7hgj3", "could not unmarshal event") } - user, err := n.view.NotifyUserByID(event.AggregateID) + user, err := n.getUserByID(event.AggregateID) if err != nil { return err } @@ -242,7 +247,7 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) { if err != nil { return err } - return n.userEvents.DomainClaimedSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID) + return n.command.UserDomainClaimedSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID) } func (n *Notification) checkIfCodeAlreadyHandledOrExpired(event *models.Event, expiry time.Duration, eventTypes ...models.EventType) (bool, error) { @@ -306,3 +311,27 @@ func (n *Notification) getLabelPolicy(ctx context.Context) (*iam_model.LabelPoli } return iam_es_model.LabelPolicyViewToModel(policy), err } + +func (n *Notification) getUserByID(userID string) (*model.NotifyUser, error) { + user, usrErr := n.view.NotifyUserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &model.NotifyUser{} + } + events, err := n.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-3n8fs", "Errors.User.NotFound") + } + return &userCopy, nil +} diff --git a/internal/notification/repository/eventsourcing/repository.go b/internal/notification/repository/eventsourcing/repository.go index cfdae2787f..548ea68297 100644 --- a/internal/notification/repository/eventsourcing/repository.go +++ b/internal/notification/repository/eventsourcing/repository.go @@ -2,6 +2,7 @@ package eventsourcing import ( es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + "github.com/caos/zitadel/internal/v2/command" "net/http" sd "github.com/caos/zitadel/internal/config/systemdefaults" @@ -29,7 +30,7 @@ type EsRepository struct { spooler *es_spol.Spooler } -func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults) (*EsRepository, error) { +func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, command *command.CommandSide) (*EsRepository, error) { es, err := es_int.Start(conf.Eventstore) if err != nil { return nil, err @@ -65,7 +66,7 @@ func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults) ( return nil, err } eventstoreRepos := handler.EventstoreRepos{UserEvents: user, OrgEvents: org, IAMEvents: iam} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, eventstoreRepos, systemDefaults, translator, dir) + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, command, eventstoreRepos, systemDefaults, translator, dir) return &EsRepository{ spool, diff --git a/internal/notification/repository/eventsourcing/spooler/spooler.go b/internal/notification/repository/eventsourcing/spooler/spooler.go index 3fe218f9dd..86255a6d46 100644 --- a/internal/notification/repository/eventsourcing/spooler/spooler.go +++ b/internal/notification/repository/eventsourcing/spooler/spooler.go @@ -2,6 +2,7 @@ package spooler import ( "database/sql" + "github.com/caos/zitadel/internal/v2/command" "net/http" sd "github.com/caos/zitadel/internal/config/systemdefaults" @@ -19,12 +20,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, eventstoreRepos handler.EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, command *command.CommandSide, eventstoreRepos handler.EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentWorkers: c.ConcurrentWorkers, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, eventstoreRepos, systemDefaults, i18n, dir), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, eventstoreRepos, systemDefaults, i18n, dir), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 6d72a857a6..07b935bca4 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -38,6 +38,9 @@ Errors: Address: NotFound: Addresse nicht gefunden NotChanged: Addresse wurde nicht geändert + Machine: + Key: + NotFound: Maschinen Key nicht gefunden NotHuman: Der Benutzer muss eine Person sein NotMachine: Der Benutzer muss technisch sein NotAllowedToLink: Der Benutzer darf nicht mit einem externen Login Provider verlinkt werden @@ -53,6 +56,7 @@ Errors: NotFound: Password nicht gefunden Empty: Passwort ist leer Invalid: Passwort ungültig + NotSet: Benutzer hat kein Passwort gesetzt PasswordComplexityPolicy: NotFound: Passwort Policy konnte nicht gefunden werden MinLength: Passwort ist zu kurz diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 9ba5001c48..eb99429d13 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -38,6 +38,9 @@ Errors: Address: NotFound: Address not found NotChanged: Address not changed + Machine: + Key: + NotFound: Machine key not found NotHuman: The User must be personal NotMachine: The User must be technical NotAllowedToLink: User is not allowed to link with external login provider @@ -53,6 +56,7 @@ Errors: NotFound: Passoword not found Empty: Password is empty Invalid: Passwort is invalid + NotSet: User has not set a password PasswordComplexityPolicy: NotFound: Password policy not found MinLength: Password is to short diff --git a/internal/ui/login/handler/auth_request.go b/internal/ui/login/handler/auth_request.go index f3c3d4b8d1..24e44eb606 100644 --- a/internal/ui/login/handler/auth_request.go +++ b/internal/ui/login/handler/auth_request.go @@ -1,17 +1,17 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" ) const ( queryAuthRequestID = "authRequestID" ) -func (l *Login) getAuthRequest(r *http.Request) (*model.AuthRequest, error) { +func (l *Login) getAuthRequest(r *http.Request) (*domain.AuthRequest, error) { authRequestID := r.FormValue(queryAuthRequestID) if authRequestID == "" { return nil, nil @@ -20,7 +20,7 @@ func (l *Login) getAuthRequest(r *http.Request) (*model.AuthRequest, error) { return l.authRepo.AuthRequestByID(r.Context(), authRequestID, userAgentID) } -func (l *Login) getAuthRequestAndParseData(r *http.Request, data interface{}) (*model.AuthRequest, error) { +func (l *Login) getAuthRequestAndParseData(r *http.Request, data interface{}) (*domain.AuthRequest, error) { authReq, err := l.getAuthRequest(r) if err != nil { return nil, err diff --git a/internal/ui/login/handler/callback_handler.go b/internal/ui/login/handler/callback_handler.go index a0209c68f6..1cdbab83e0 100644 --- a/internal/ui/login/handler/callback_handler.go +++ b/internal/ui/login/handler/callback_handler.go @@ -1,12 +1,11 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" - - "github.com/caos/zitadel/internal/auth_request/model" ) -func (l *Login) redirectToCallback(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) redirectToCallback(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { callback := l.oidcAuthCallbackURL + authReq.ID http.Redirect(w, r, callback, http.StatusFound) } diff --git a/internal/ui/login/handler/change_password_handler.go b/internal/ui/login/handler/change_password_handler.go index d85f537e08..88167dbe1a 100644 --- a/internal/ui/login/handler/change_password_handler.go +++ b/internal/ui/login/handler/change_password_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -26,7 +26,7 @@ func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.ChangePassword(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.OldPassword, data.NewPassword, userAgentID) + err = l.command.ChangePassword(setContext(r.Context(), authReq.UserOrgID), authReq.UserOrgID, authReq.UserID, data.OldPassword, data.NewPassword, userAgentID) if err != nil { l.renderChangePassword(w, r, authReq, err) return @@ -34,7 +34,7 @@ func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) { l.renderChangePasswordDone(w, r, authReq) } -func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -63,7 +63,7 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePassword], data, nil) } -func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { var errType, errMessage string data := l.getUserData(r, authReq, "Password Change Done", errType, errMessage) l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePasswordDone], data, nil) diff --git a/internal/ui/login/handler/external_login_handler.go b/internal/ui/login/handler/external_login_handler.go index 1d7455e91f..c640319818 100644 --- a/internal/ui/login/handler/external_login_handler.go +++ b/internal/ui/login/handler/external_login_handler.go @@ -4,14 +4,11 @@ import ( "github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/rp" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/errors" caos_errors "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/eventstore/models" iam_model "github.com/caos/zitadel/internal/iam/model" - org_model "github.com/caos/zitadel/internal/org/model" - usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/v2/domain" "net/http" "strings" "time" @@ -41,7 +38,7 @@ type externalNotFoundOptionData struct { baseData } -func (l *Login) handleExternalLoginStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, selectedIDPConfigID string) { +func (l *Login) handleExternalLoginStep(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, selectedIDPConfigID string) { for _, idp := range authReq.AllowedExternalIDPs { if idp.IDPConfigID == selectedIDPConfigID { l.handleIDP(w, r, authReq, selectedIDPConfigID) @@ -65,7 +62,7 @@ func (l *Login) handleExternalLogin(w http.ResponseWriter, r *http.Request) { l.handleIDP(w, r, authReq, data.IDPConfigID) } -func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, selectedIDPConfigID string) { +func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, selectedIDPConfigID string) { idpConfig, err := l.getIDPConfigByID(r, selectedIDPConfigID) if err != nil { l.renderError(w, r, authReq, err) @@ -84,7 +81,7 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *model l.handleOIDCAuthorize(w, r, authReq, idpConfig, EndpointExternalLoginCallback) } -func (l *Login) handleOIDCAuthorize(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, idpConfig *iam_model.IDPConfigView, callbackEndpoint string) { +func (l *Login) handleOIDCAuthorize(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, callbackEndpoint string) { provider := l.getRPConfig(w, r, authReq, idpConfig, callbackEndpoint) http.Redirect(w, r, rp.AuthURL(authReq.ID, provider, rp.WithPrompt(oidc.PromptSelectAccount)), http.StatusFound) } @@ -116,7 +113,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque l.handleExternalUserAuthenticated(w, r, authReq, idpConfig, userAgentID, tokens) } -func (l *Login) getRPConfig(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, idpConfig *iam_model.IDPConfigView, callbackEndpoint string) rp.RelayingParty { +func (l *Login) getRPConfig(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, callbackEndpoint string) rp.RelayingParty { oidcClientSecret, err := crypto.DecryptString(idpConfig.OIDCClientSecret, l.IDPConfigAesCrypto) if err != nil { l.renderError(w, r, authReq, err) @@ -130,9 +127,9 @@ func (l *Login) getRPConfig(w http.ResponseWriter, r *http.Request, authReq *mod return provider } -func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) { +func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) { externalUser := l.mapTokenToLoginUser(tokens, idpConfig) - err := l.authRepo.CheckExternalUserLogin(r.Context(), authReq.ID, userAgentID, externalUser, model.BrowserInfoFromRequest(r)) + err := l.authRepo.CheckExternalUserLogin(r.Context(), authReq.ID, userAgentID, externalUser, domain.BrowserInfoFromRequest(r)) if err != nil { if errors.IsNotFound(err) { err = nil @@ -143,7 +140,7 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R l.renderNextStep(w, r, authReq) } -func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -176,7 +173,7 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http l.handleAutoRegister(w, r, authReq) } -func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { iam, err := l.authRepo.GetIAM(r.Context()) if err != nil { l.renderExternalNotFoundOption(w, r, authReq, err) @@ -184,13 +181,10 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR } resourceOwner := iam.GlobalOrgID - member := &org_model.OrgMember{ - ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID}, - Roles: []string{orgProjectCreatorRole}, - } + memberRoles := []string{domain.RoleOrgProjectCreator} if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID { - member = nil + memberRoles = nil resourceOwner = authReq.RequestedOrgID } @@ -208,7 +202,7 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) user, externalIDP := l.mapExternalUserToLoginUser(orgIamPolicy, authReq.LinkingUsers[len(authReq.LinkingUsers)-1], idpConfig) - err = l.authRepo.AutoRegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, member, authReq.ID, userAgentID, resourceOwner, model.BrowserInfoFromRequest(r)) + err = l.authRepo.AutoRegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, memberRoles, authReq.ID, userAgentID, resourceOwner, domain.BrowserInfoFromRequest(r)) if err != nil { l.renderExternalNotFoundOption(w, r, authReq, err) return @@ -216,7 +210,7 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR l.renderNextStep(w, r, authReq) } -func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) *model.ExternalUser { +func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) *domain.ExternalUser { displayName := tokens.IDTokenClaims.GetPreferredUsername() if displayName == "" && tokens.IDTokenClaims.GetEmail() != "" { displayName = tokens.IDTokenClaims.GetEmail() @@ -228,7 +222,7 @@ func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.ID } } - externalUser := &model.ExternalUser{ + externalUser := &domain.ExternalUser{ IDPConfigID: idpConfig.IDPConfigID, ExternalUserID: tokens.IDTokenClaims.GetSubject(), PreferredUsername: tokens.IDTokenClaims.GetPreferredUsername(), @@ -246,7 +240,7 @@ func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.ID } return externalUser } -func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *iam_model.OrgIAMPolicyView, linkingUser *model.ExternalUser, idpConfig *iam_model.IDPConfigView) (*usr_model.User, *usr_model.ExternalIDP) { +func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *iam_model.OrgIAMPolicyView, linkingUser *domain.ExternalUser, idpConfig *iam_model.IDPConfigView) (*domain.Human, *domain.ExternalIDP) { username := linkingUser.PreferredUsername switch idpConfig.OIDCUsernameMapping { case iam_model.OIDCMappingFieldEmail: @@ -262,23 +256,21 @@ func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *iam_model.OrgIAMPolicyV } } - user := &usr_model.User{ - UserName: username, - Human: &usr_model.Human{ - Profile: &usr_model.Profile{ - FirstName: linkingUser.FirstName, - LastName: linkingUser.LastName, - PreferredLanguage: linkingUser.PreferredLanguage, - NickName: linkingUser.NickName, - }, - Email: &usr_model.Email{ - EmailAddress: linkingUser.Email, - IsEmailVerified: linkingUser.IsEmailVerified, - }, + human := &domain.Human{ + Username: username, + Profile: &domain.Profile{ + FirstName: linkingUser.FirstName, + LastName: linkingUser.LastName, + PreferredLanguage: linkingUser.PreferredLanguage, + NickName: linkingUser.NickName, + }, + Email: &domain.Email{ + EmailAddress: linkingUser.Email, + IsEmailVerified: linkingUser.IsEmailVerified, }, } if linkingUser.Phone != "" { - user.Phone = &usr_model.Phone{ + human.Phone = &domain.Phone{ PhoneNumber: linkingUser.Phone, IsPhoneVerified: linkingUser.IsPhoneVerified, } @@ -292,10 +284,10 @@ func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *iam_model.OrgIAMPolicyV } } - externalIDP := &usr_model.ExternalIDP{ - IDPConfigID: idpConfig.IDPConfigID, - UserID: linkingUser.ExternalUserID, - DisplayName: displayName, + externalIDP := &domain.ExternalIDP{ + IDPConfigID: idpConfig.IDPConfigID, + ExternalUserID: linkingUser.ExternalUserID, + DisplayName: displayName, } - return user, externalIDP + return human, externalIDP } diff --git a/internal/ui/login/handler/external_register_handler.go b/internal/ui/login/handler/external_register_handler.go index 3d2834bb47..b1907df24a 100644 --- a/internal/ui/login/handler/external_register_handler.go +++ b/internal/ui/login/handler/external_register_handler.go @@ -1,20 +1,15 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" "strings" "github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/rp" - "golang.org/x/text/language" - http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" caos_errors "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/eventstore/models" iam_model "github.com/caos/zitadel/internal/iam/model" - org_model "github.com/caos/zitadel/internal/org/model" - usr_model "github.com/caos/zitadel/internal/user/model" ) func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) { @@ -73,20 +68,17 @@ func (l *Login) handleExternalRegisterCallback(w http.ResponseWriter, r *http.Re l.handleExternalUserRegister(w, r, authReq, idpConfig, userAgentID, tokens) } -func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) { +func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) { iam, err := l.authRepo.GetIAM(r.Context()) if err != nil { l.renderRegisterOption(w, r, authReq, err) return } resourceOwner := iam.GlobalOrgID - member := &org_model.OrgMember{ - ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID}, - Roles: []string{orgProjectCreatorRole}, - } + memberRoles := []string{domain.RoleOrgProjectCreator} if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID { - member = nil + memberRoles = nil resourceOwner = authReq.RequestedOrgID } orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner) @@ -94,8 +86,8 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques l.renderRegisterOption(w, r, authReq, err) return } - user, externalIDP := l.mapTokenToLoginUserAndExternalIDP(orgIamPolicy, tokens, idpConfig) - _, err = l.authRepo.RegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, member, resourceOwner) + user, externalIDP := l.mapTokenToLoginHumanAndExternalIDP(orgIamPolicy, tokens, idpConfig) + _, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, memberRoles) if err != nil { l.renderRegisterOption(w, r, authReq, err) return @@ -103,7 +95,7 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques l.renderNextStep(w, r, authReq) } -func (l *Login) mapTokenToLoginUserAndExternalIDP(orgIamPolicy *iam_model.OrgIAMPolicyView, tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) (*usr_model.User, *usr_model.ExternalIDP) { +func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *iam_model.OrgIAMPolicyView, tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) (*domain.Human, *domain.ExternalIDP) { username := tokens.IDTokenClaims.GetPreferredUsername() switch idpConfig.OIDCUsernameMapping { case iam_model.OIDCMappingFieldEmail: @@ -119,23 +111,22 @@ func (l *Login) mapTokenToLoginUserAndExternalIDP(orgIamPolicy *iam_model.OrgIAM } } - user := &usr_model.User{ - UserName: username, - Human: &usr_model.Human{ - Profile: &usr_model.Profile{ - FirstName: tokens.IDTokenClaims.GetGivenName(), - LastName: tokens.IDTokenClaims.GetFamilyName(), - PreferredLanguage: language.Tag(tokens.IDTokenClaims.GetLocale()), - NickName: tokens.IDTokenClaims.GetNickname(), - }, - Email: &usr_model.Email{ - EmailAddress: tokens.IDTokenClaims.GetEmail(), - IsEmailVerified: tokens.IDTokenClaims.IsEmailVerified(), - }, + human := &domain.Human{ + Username: username, + Profile: &domain.Profile{ + FirstName: tokens.IDTokenClaims.GetGivenName(), + LastName: tokens.IDTokenClaims.GetFamilyName(), + PreferredLanguage: tokens.IDTokenClaims.GetLocale(), + NickName: tokens.IDTokenClaims.GetNickname(), + }, + Email: &domain.Email{ + EmailAddress: tokens.IDTokenClaims.GetEmail(), + IsEmailVerified: tokens.IDTokenClaims.IsEmailVerified(), }, } + if tokens.IDTokenClaims.GetPhoneNumber() != "" { - user.Phone = &usr_model.Phone{ + human.Phone = &domain.Phone{ PhoneNumber: tokens.IDTokenClaims.GetPhoneNumber(), IsPhoneVerified: tokens.IDTokenClaims.IsPhoneNumberVerified(), } @@ -149,10 +140,10 @@ func (l *Login) mapTokenToLoginUserAndExternalIDP(orgIamPolicy *iam_model.OrgIAM } } - externalIDP := &usr_model.ExternalIDP{ - IDPConfigID: idpConfig.IDPConfigID, - UserID: tokens.IDTokenClaims.GetSubject(), - DisplayName: displayName, + externalIDP := &domain.ExternalIDP{ + IDPConfigID: idpConfig.IDPConfigID, + ExternalUserID: tokens.IDTokenClaims.GetSubject(), + DisplayName: displayName, } - return user, externalIDP + return human, externalIDP } diff --git a/internal/ui/login/handler/init_password_handler.go b/internal/ui/login/handler/init_password_handler.go index 21d9cfe080..7348babf15 100644 --- a/internal/ui/login/handler/init_password_handler.go +++ b/internal/ui/login/handler/init_password_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/errors" ) @@ -58,18 +58,18 @@ func (l *Login) handleInitPasswordCheck(w http.ResponseWriter, r *http.Request) l.checkPWCode(w, r, authReq, data, nil) } -func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *initPasswordFormData, err error) { +func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *initPasswordFormData, err error) { if data.Password != data.PasswordConfirm { err := errors.ThrowInvalidArgument(nil, "VIEW-KaGue", "Errors.User.Password.ConfirmationWrong") l.renderInitPassword(w, r, authReq, data.UserID, data.Code, err) return } - userOrg := login + userOrg := "" if authReq != nil { userOrg = authReq.UserOrgID } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.SetPassword(setContext(r.Context(), userOrg), data.UserID, data.Code, data.Password, userAgentID) + err = l.command.SetPassword(setContext(r.Context(), userOrg), userOrg, data.UserID, data.Code, data.Password, userAgentID) if err != nil { l.renderInitPassword(w, r, authReq, data.UserID, "", err) return @@ -77,16 +77,25 @@ func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *mod l.renderInitPasswordDone(w, r, authReq) } -func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { + if authReq == nil { + l.renderError(w, r, nil, errors.ThrowInternal(nil, "LOGIN-8sn7s", "Errors.AuthRequest.NotFound")) + return + } userOrg := login if authReq != nil { userOrg = authReq.UserOrgID } - err := l.authRepo.RequestPasswordReset(setContext(r.Context(), userOrg), authReq.LoginName) + user, err := l.authRepo.UserByLoginName(setContext(r.Context(), userOrg), authReq.LoginName) + if err != nil { + l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) + return + } + err = l.command.RequestSetPassword(setContext(r.Context(), userOrg), user.ID, user.ResourceOwner, domain.NotificationTypeEmail) l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) } -func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string, err error) { +func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, code string, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -121,7 +130,7 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPassword], data, nil) } -func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { data := l.getUserData(r, authReq, "Password Init Done", "", "") l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPasswordDone], data, nil) } diff --git a/internal/ui/login/handler/init_user_handler.go b/internal/ui/login/handler/init_user_handler.go index 862666e089..94e9485c41 100644 --- a/internal/ui/login/handler/init_user_handler.go +++ b/internal/ui/login/handler/init_user_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" "strconv" - "github.com/caos/zitadel/internal/auth_request/model" caos_errs "github.com/caos/zitadel/internal/errors" ) @@ -62,17 +62,17 @@ func (l *Login) handleInitUserCheck(w http.ResponseWriter, r *http.Request) { l.checkUserInitCode(w, r, authReq, data, nil) } -func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *initUserFormData, err error) { +func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *initUserFormData, err error) { if data.Password != data.PasswordConfirm { err := caos_errs.ThrowInvalidArgument(nil, "VIEW-fsdfd", "Errors.User.Password.ConfirmationWrong") l.renderInitUser(w, r, authReq, data.UserID, data.Code, data.PasswordSet, err) return } - userOrgID := login + userOrgID := "" if authReq != nil { userOrgID = authReq.UserOrgID } - err = l.authRepo.VerifyInitCode(setContext(r.Context(), userOrgID), data.UserID, data.Code, data.Password) + err = l.command.HumanVerifyInitCode(setContext(r.Context(), userOrgID), data.UserID, userOrgID, data.Code, data.Password) if err != nil { l.renderInitUser(w, r, authReq, data.UserID, "", data.PasswordSet, err) return @@ -80,16 +80,16 @@ func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authRe l.renderInitUserDone(w, r, authReq) } -func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID string, showPassword bool) { - userOrgID := login +func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID string, showPassword bool) { + userOrgID := "" if authReq != nil { userOrgID = authReq.UserOrgID } - err := l.authRepo.ResendInitVerificationMail(setContext(r.Context(), userOrgID), userID) + err := l.command.ResendInitialMail(setContext(r.Context(), userOrgID), userID, "", userOrgID) l.renderInitUser(w, r, authReq, userID, "", showPassword, err) } -func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string, passwordSet bool, err error) { +func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, code string, passwordSet bool, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -124,7 +124,7 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq * l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUser], data, nil) } -func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { data := l.getUserData(r, authReq, "User Init Done", "", "") l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUserDone], data, nil) } diff --git a/internal/ui/login/handler/link_users_handler.go b/internal/ui/login/handler/link_users_handler.go index 62346cf4ad..c1ca76a934 100644 --- a/internal/ui/login/handler/link_users_handler.go +++ b/internal/ui/login/handler/link_users_handler.go @@ -2,22 +2,21 @@ package handler import ( http_mw "github.com/caos/zitadel/internal/api/http/middleware" + "github.com/caos/zitadel/internal/v2/domain" "net/http" - - "github.com/caos/zitadel/internal/auth_request/model" ) const ( tmplLinkUsersDone = "linkusersdone" ) -func (l *Login) linkUsers(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) linkUsers(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.LinkExternalUsers(setContext(r.Context(), authReq.UserOrgID), authReq.ID, userAgentID, model.BrowserInfoFromRequest(r)) + err = l.authRepo.LinkExternalUsers(setContext(r.Context(), authReq.UserOrgID), authReq.ID, userAgentID, domain.BrowserInfoFromRequest(r)) l.renderLinkUsersDone(w, r, authReq, err) } -func (l *Login) renderLinkUsersDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderLinkUsersDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string data := l.getUserData(r, authReq, "Linking Users Done", errType, errMessage) l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLinkUsersDone], data, nil) diff --git a/internal/ui/login/handler/login_handler.go b/internal/ui/login/handler/login_handler.go index 7c68ce0ddb..bb7d3c2a66 100644 --- a/internal/ui/login/handler/login_handler.go +++ b/internal/ui/login/handler/login_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -62,7 +62,7 @@ func (l *Login) handleLoginNameCheck(w http.ResponseWriter, r *http.Request) { l.renderNextStep(w, r, authReq) } -func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) diff --git a/internal/ui/login/handler/mail_verify_handler.go b/internal/ui/login/handler/mail_verify_handler.go index 3e95714add..58f81f96c4 100644 --- a/internal/ui/login/handler/mail_verify_handler.go +++ b/internal/ui/login/handler/mail_verify_handler.go @@ -1,9 +1,8 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" - - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -47,21 +46,21 @@ func (l *Login) handleMailVerificationCheck(w http.ResponseWriter, r *http.Reque l.checkMailCode(w, r, authReq, data.UserID, data.Code) return } - userOrg := login + userOrg := "" if authReq != nil { userOrg = authReq.UserOrgID } - err = l.authRepo.ResendEmailVerificationMail(setContext(r.Context(), userOrg), data.UserID) + err = l.command.CreateHumanEmailVerificationCode(setContext(r.Context(), userOrg), data.UserID, userOrg) l.renderMailVerification(w, r, authReq, data.UserID, err) } -func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string) { - userOrg := login +func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, code string) { + userOrg := "" if authReq != nil { userID = authReq.UserID userOrg = authReq.UserOrgID } - err := l.authRepo.VerifyEmail(setContext(r.Context(), userOrg), userID, code) + err := l.command.VerifyHumanEmail(setContext(r.Context(), userOrg), userID, code, userOrg) if err != nil { l.renderMailVerification(w, r, authReq, userID, err) return @@ -69,7 +68,7 @@ func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *m l.renderMailVerified(w, r, authReq) } -func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID string, err error) { +func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID string, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -85,7 +84,7 @@ func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, a l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerification], data, nil) } -func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { data := mailVerificationData{ baseData: l.getBaseData(r, authReq, "Mail Verified", "", ""), profileData: l.getProfileData(authReq), diff --git a/internal/ui/login/handler/mfa_init_done_handler.go b/internal/ui/login/handler/mfa_init_done_handler.go index 741a010677..01509935ac 100644 --- a/internal/ui/login/handler/mfa_init_done_handler.go +++ b/internal/ui/login/handler/mfa_init_done_handler.go @@ -1,9 +1,8 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" - - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -13,7 +12,7 @@ const ( type mfaInitDoneData struct { } -func (l *Login) renderMFAInitDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaDoneData) { +func (l *Login) renderMFAInitDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaDoneData) { var errType, errMessage string data.baseData = l.getBaseData(r, authReq, "MFA Init Done", errType, errMessage) data.profileData = l.getProfileData(authReq) diff --git a/internal/ui/login/handler/mfa_init_u2f.go b/internal/ui/login/handler/mfa_init_u2f.go index 1e5d64f08f..370d062413 100644 --- a/internal/ui/login/handler/mfa_init_u2f.go +++ b/internal/ui/login/handler/mfa_init_u2f.go @@ -2,11 +2,11 @@ package handler import ( "encoding/base64" + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" "github.com/caos/zitadel/internal/auth_request/model" - user_model "github.com/caos/zitadel/internal/user/model" ) const ( @@ -18,11 +18,11 @@ type u2fInitData struct { MFAType model.MFAType } -func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage, credentialData string - var u2f *user_model.WebAuthNToken + var u2f *domain.WebAuthNToken if err == nil { - u2f, err = l.authRepo.AddMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID) + u2f, err = l.command.HumanAddU2FSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, true) } if err != nil { errMessage = l.getErrorMessage(r, err) @@ -54,12 +54,12 @@ func (l *Login) handleRegisterU2F(w http.ResponseWriter, r *http.Request) { } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - if err = l.authRepo.VerifyMFAU2FSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Name, userAgentID, credData); err != nil { + if err = l.command.HumanVerifyU2FSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, data.Name, userAgentID, credData); err != nil { l.renderRegisterU2F(w, r, authReq, err) return } done := &mfaDoneData{ - MFAType: model.MFATypeU2F, + MFAType: domain.MFATypeU2F, } l.renderMFAInitDone(w, r, authReq, done) } diff --git a/internal/ui/login/handler/mfa_init_verify_handler.go b/internal/ui/login/handler/mfa_init_verify_handler.go index 92ff320541..888b4b828f 100644 --- a/internal/ui/login/handler/mfa_init_verify_handler.go +++ b/internal/ui/login/handler/mfa_init_verify_handler.go @@ -2,13 +2,13 @@ package handler import ( "bytes" + "github.com/caos/zitadel/internal/v2/domain" "net/http" svg "github.com/ajstarks/svgo" "github.com/boombuler/barcode/qr" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/qrcode" ) @@ -17,10 +17,10 @@ const ( ) type mfaInitVerifyData struct { - MFAType model.MFAType `schema:"mfaType"` - Code string `schema:"code"` - URL string `schema:"url"` - Secret string `schema:"secret"` + MFAType domain.MFAType `schema:"mfaType"` + Code string `schema:"code"` + URL string `schema:"url"` + Secret string `schema:"secret"` } func (l *Login) handleMFAInitVerify(w http.ResponseWriter, r *http.Request) { @@ -32,7 +32,7 @@ func (l *Login) handleMFAInitVerify(w http.ResponseWriter, r *http.Request) { } var verifyData *mfaVerifyData switch data.MFAType { - case model.MFATypeOTP: + case domain.MFATypeOTP: verifyData = l.handleOTPVerify(w, r, authReq, data) } @@ -47,9 +47,9 @@ func (l *Login) handleMFAInitVerify(w http.ResponseWriter, r *http.Request) { l.renderMFAInitDone(w, r, authReq, done) } -func (l *Login) handleOTPVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaInitVerifyData) *mfaVerifyData { +func (l *Login) handleOTPVerify(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaInitVerifyData) *mfaVerifyData { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err := l.authRepo.VerifyMFAOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code, userAgentID) + err := l.command.HumanCheckMFAOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code, userAgentID, authReq.UserOrgID) if err == nil { return nil } @@ -64,14 +64,14 @@ func (l *Login) handleOTPVerify(w http.ResponseWriter, r *http.Request, authReq return mfadata } -func (l *Login) renderMFAInitVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData, err error) { +func (l *Login) renderMFAInitVerify(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaVerifyData, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) } data.baseData = l.getBaseData(r, authReq, "MFA Init Verify", errType, errMessage) data.profileData = l.getProfileData(authReq) - if data.MFAType == model.MFATypeOTP { + if data.MFAType == domain.MFATypeOTP { code, err := generateQrCode(data.otpData.Url) if err == nil { data.otpData.QrCode = code diff --git a/internal/ui/login/handler/mfa_prompt_handler.go b/internal/ui/login/handler/mfa_prompt_handler.go index 32a32a00db..e42508c907 100644 --- a/internal/ui/login/handler/mfa_prompt_handler.go +++ b/internal/ui/login/handler/mfa_prompt_handler.go @@ -1,9 +1,9 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" - "github.com/caos/zitadel/internal/auth_request/model" caos_errs "github.com/caos/zitadel/internal/errors" ) @@ -12,8 +12,8 @@ const ( ) type mfaPromptData struct { - MFAProvider model.MFAType `schema:"provider"` - Skip bool `schema:"skip"` + MFAProvider domain.MFAType `schema:"provider"` + Skip bool `schema:"skip"` } func (l *Login) handleMFAPrompt(w http.ResponseWriter, r *http.Request) { @@ -29,7 +29,7 @@ func (l *Login) handleMFAPrompt(w http.ResponseWriter, r *http.Request) { l.handleMFACreation(w, r, authReq, mfaVerifyData) return } - err = l.authRepo.SkipMFAInit(setContext(r.Context(), authReq.UserOrgID), authReq.UserID) + err = l.command.HumanSkipMFAInit(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID) if err != nil { l.renderError(w, r, authReq, err) return @@ -48,7 +48,7 @@ func (l *Login) handleMFAPromptSelection(w http.ResponseWriter, r *http.Request) l.renderNextStep(w, r, authReq) } -func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, mfaPromptData *model.MFAPromptStep, err error) { +func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, mfaPromptData *domain.MFAPromptStep, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -76,20 +76,20 @@ func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAPrompt], data, nil) } -func (l *Login) handleMFACreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) { +func (l *Login) handleMFACreation(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaVerifyData) { switch data.MFAType { - case model.MFATypeOTP: + case domain.MFATypeOTP: l.handleOTPCreation(w, r, authReq, data) return - case model.MFATypeU2F: + case domain.MFATypeU2F: l.renderRegisterU2F(w, r, authReq, nil) return } l.renderError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-Or3HO", "Errors.User.MFA.NoProviders")) } -func (l *Login) handleOTPCreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) { - otp, err := l.authRepo.AddMFAOTP(setContext(r.Context(), authReq.UserOrgID), authReq.UserID) +func (l *Login) handleOTPCreation(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaVerifyData) { + otp, err := l.command.AddHumanOTP(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID) if err != nil { l.renderError(w, r, authReq, err) return diff --git a/internal/ui/login/handler/mfa_verify_handler.go b/internal/ui/login/handler/mfa_verify_handler.go index 3d284e01aa..fee297b963 100644 --- a/internal/ui/login/handler/mfa_verify_handler.go +++ b/internal/ui/login/handler/mfa_verify_handler.go @@ -1,6 +1,7 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" @@ -25,7 +26,7 @@ func (l *Login) handleMFAVerify(w http.ResponseWriter, r *http.Request) { } if data.MFAType == model.MFATypeOTP { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.VerifyMFAOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Code, userAgentID, model.BrowserInfoFromRequest(r)) + err = l.authRepo.VerifyMFAOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, authReq.UserOrgID, data.Code, userAgentID, domain.BrowserInfoFromRequest(r)) } if err != nil { l.renderError(w, r, authReq, err) @@ -34,7 +35,7 @@ func (l *Login) handleMFAVerify(w http.ResponseWriter, r *http.Request) { l.renderNextStep(w, r, authReq) } -func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MFAVerificationStep, err error) { +func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, verificationStep *domain.MFAVerificationStep, err error) { if verificationStep == nil { l.renderError(w, r, authReq, err) return @@ -43,7 +44,7 @@ func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq l.renderMFAVerifySelected(w, r, authReq, verificationStep, provider, err) } -func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MFAVerificationStep, selectedProvider model.MFAType, err error) { +func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, verificationStep *domain.MFAVerificationStep, selectedProvider domain.MFAType, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -54,12 +55,12 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, return } switch selectedProvider { - case model.MFATypeU2F: - l.renderU2FVerification(w, r, authReq, removeSelectedProviderFromList(verificationStep.MFAProviders, model.MFATypeU2F), nil) + case domain.MFATypeU2F: + l.renderU2FVerification(w, r, authReq, removeSelectedProviderFromList(verificationStep.MFAProviders, domain.MFATypeU2F), nil) return - case model.MFATypeOTP: - data.MFAProviders = removeSelectedProviderFromList(verificationStep.MFAProviders, model.MFATypeOTP) - data.SelectedMFAProvider = model.MFATypeOTP + case domain.MFATypeOTP: + data.MFAProviders = removeSelectedProviderFromList(verificationStep.MFAProviders, domain.MFATypeOTP) + data.SelectedMFAProvider = domain.MFATypeOTP default: l.renderError(w, r, authReq, err) return @@ -67,7 +68,7 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAVerify], data, nil) } -func removeSelectedProviderFromList(providers []model.MFAType, selected model.MFAType) []model.MFAType { +func removeSelectedProviderFromList(providers []domain.MFAType, selected domain.MFAType) []domain.MFAType { for i := len(providers) - 1; i >= 0; i-- { if providers[i] == selected { copy(providers[i:], providers[i+1:]) diff --git a/internal/ui/login/handler/mfa_verify_u2f_handler.go b/internal/ui/login/handler/mfa_verify_u2f_handler.go index 1ac79846a5..d8261b2814 100644 --- a/internal/ui/login/handler/mfa_verify_u2f_handler.go +++ b/internal/ui/login/handler/mfa_verify_u2f_handler.go @@ -2,11 +2,10 @@ package handler import ( "encoding/base64" + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" - user_model "github.com/caos/zitadel/internal/user/model" ) const ( @@ -15,21 +14,21 @@ const ( type mfaU2FData struct { webAuthNData - MFAProviders []model.MFAType - SelectedProvider model.MFAType + MFAProviders []domain.MFAType + SelectedProvider domain.MFAType } type mfaU2FFormData struct { webAuthNFormData - SelectedProvider model.MFAType `schema:"provider"` + SelectedProvider domain.MFAType `schema:"provider"` } -func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, providers []model.MFAType, err error) { +func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, err error) { var errType, errMessage, credentialData string - var webAuthNLogin *user_model.WebAuthNLogin + var webAuthNLogin *domain.WebAuthNLogin if err == nil { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - webAuthNLogin, err = l.authRepo.BeginMFAU2FLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID) + webAuthNLogin, err = l.authRepo.BeginMFAU2FLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID) } if err != nil { errMessage = l.getErrorMessage(r, err) @@ -55,7 +54,7 @@ func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) { l.renderError(w, r, authReq, err) return } - step, ok := authReq.PossibleSteps[0].(*model.MFAVerificationStep) + step, ok := authReq.PossibleSteps[0].(*domain.MFAVerificationStep) if !ok { l.renderError(w, r, authReq, err) return @@ -70,7 +69,7 @@ func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.VerifyMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID, credData, model.BrowserInfoFromRequest(r)) + err = l.authRepo.VerifyMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID, credData, domain.BrowserInfoFromRequest(r)) if err != nil { l.renderU2FVerification(w, r, authReq, step.MFAProviders, err) return diff --git a/internal/ui/login/handler/password_handler.go b/internal/ui/login/handler/password_handler.go index 971f50d18d..5cfd0a6a38 100644 --- a/internal/ui/login/handler/password_handler.go +++ b/internal/ui/login/handler/password_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -15,7 +15,7 @@ type passwordFormData struct { Password string `schema:"password"` } -func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -32,7 +32,7 @@ func (l *Login) handlePasswordCheck(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.VerifyPassword(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Password, userAgentID, model.BrowserInfoFromRequest(r)) + err = l.authRepo.VerifyPassword(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, authReq.UserOrgID, data.Password, userAgentID, domain.BrowserInfoFromRequest(r)) if err != nil { l.renderPassword(w, r, authReq, err) return diff --git a/internal/ui/login/handler/password_reset_handler.go b/internal/ui/login/handler/password_reset_handler.go index 524c1094e5..359598491c 100644 --- a/internal/ui/login/handler/password_reset_handler.go +++ b/internal/ui/login/handler/password_reset_handler.go @@ -1,9 +1,8 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" - - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -16,11 +15,16 @@ func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) { l.renderError(w, r, authReq, err) return } - err = l.authRepo.RequestPasswordReset(setContext(r.Context(), authReq.UserOrgID), authReq.LoginName) + user, err := l.authRepo.UserByLoginName(setContext(r.Context(), authReq.UserOrgID), authReq.LoginName) + if err != nil { + l.renderPasswordResetDone(w, r, authReq, err) + return + } + err = l.command.RequestSetPassword(setContext(r.Context(), authReq.UserOrgID), user.ID, authReq.UserOrgID, domain.NotificationTypeEmail) l.renderPasswordResetDone(w, r, authReq, err) } -func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) diff --git a/internal/ui/login/handler/passwordless_login_handler.go b/internal/ui/login/handler/passwordless_login_handler.go index 7523e3d1f6..597ea7c325 100644 --- a/internal/ui/login/handler/passwordless_login_handler.go +++ b/internal/ui/login/handler/passwordless_login_handler.go @@ -2,11 +2,10 @@ package handler import ( "encoding/base64" + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" - user_model "github.com/caos/zitadel/internal/user/model" ) const ( @@ -23,12 +22,12 @@ type passwordlessFormData struct { PasswordLogin bool `schema:"passwordlogin"` } -func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage, credentialData string - var webAuthNLogin *user_model.WebAuthNLogin + var webAuthNLogin *domain.WebAuthNLogin if err == nil { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - webAuthNLogin, err = l.authRepo.BeginPasswordlessLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID) + webAuthNLogin, err = l.authRepo.BeginPasswordlessLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID) } if err != nil { errMessage = l.getErrorMessage(r, err) @@ -67,7 +66,7 @@ func (l *Login) handlePasswordlessVerification(w http.ResponseWriter, r *http.Re return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - err = l.authRepo.VerifyPasswordless(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID, credData, model.BrowserInfoFromRequest(r)) + err = l.authRepo.VerifyPasswordless(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID, credData, domain.BrowserInfoFromRequest(r)) if err != nil { l.renderPasswordlessVerification(w, r, authReq, err) return diff --git a/internal/ui/login/handler/register_handler.go b/internal/ui/login/handler/register_handler.go index ffb9d91731..890956a5a0 100644 --- a/internal/ui/login/handler/register_handler.go +++ b/internal/ui/login/handler/register_handler.go @@ -1,20 +1,16 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" "golang.org/x/text/language" - "github.com/caos/zitadel/internal/auth_request/model" caos_errs "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" - usr_model "github.com/caos/zitadel/internal/user/model" ) const ( - tmplRegister = "register" - orgProjectCreatorRole = "ORG_PROJECT_CREATOR" + tmplRegister = "register" ) type registerFormData struct { @@ -68,15 +64,13 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) { } resourceOwner := iam.GlobalOrgID - member := &org_model.OrgMember{ - ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID}, - Roles: []string{orgProjectCreatorRole}, - } + memberRoles := []string{domain.RoleOrgProjectCreator} + if authRequest.RequestedOrgID != "" && authRequest.RequestedOrgID != iam.GlobalOrgID { - member = nil + memberRoles = nil resourceOwner = authRequest.RequestedOrgID } - user, err := l.authRepo.Register(setContext(r.Context(), resourceOwner), data.toUserModel(), member, resourceOwner) + user, err := l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, data.toHumanDomain(), nil, memberRoles) if err != nil { l.renderRegister(w, r, authRequest, data, err) return @@ -89,7 +83,7 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) { l.renderNextStep(w, r, authRequest) } -func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authRequest *model.AuthRequest, formData *registerFormData, err error) { +func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authRequest *domain.AuthRequest, formData *registerFormData, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -142,21 +136,19 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplRegister], data, funcs) } -func (d registerFormData) toUserModel() *usr_model.User { - return &usr_model.User{ - Human: &usr_model.Human{ - Profile: &usr_model.Profile{ - FirstName: d.Firstname, - LastName: d.Lastname, - PreferredLanguage: language.Make(d.Language), - Gender: usr_model.Gender(d.Gender), - }, - Password: &usr_model.Password{ - SecretString: d.Password, - }, - Email: &usr_model.Email{ - EmailAddress: d.Email, - }, +func (d registerFormData) toHumanDomain() *domain.Human { + return &domain.Human{ + Profile: &domain.Profile{ + FirstName: d.Firstname, + LastName: d.Lastname, + PreferredLanguage: language.Make(d.Language), + Gender: domain.Gender(d.Gender), + }, + Password: &domain.Password{ + SecretString: d.Password, + }, + Email: &domain.Email{ + EmailAddress: d.Email, }, } } diff --git a/internal/ui/login/handler/register_option_handler.go b/internal/ui/login/handler/register_option_handler.go index 254b258b4f..c3ad5e8399 100644 --- a/internal/ui/login/handler/register_option_handler.go +++ b/internal/ui/login/handler/register_option_handler.go @@ -1,7 +1,7 @@ package handler import ( - "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/v2/domain" "net/http" ) @@ -27,7 +27,7 @@ func (l *Login) handleRegisterOption(w http.ResponseWriter, r *http.Request) { l.renderRegisterOption(w, r, authRequest, nil) } -func (l *Login) renderRegisterOption(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderRegisterOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) diff --git a/internal/ui/login/handler/register_org_handler.go b/internal/ui/login/handler/register_org_handler.go index ea2f7a739d..aebdaba3bb 100644 --- a/internal/ui/login/handler/register_org_handler.go +++ b/internal/ui/login/handler/register_org_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" auth_model "github.com/caos/zitadel/internal/auth/model" - "github.com/caos/zitadel/internal/auth_request/model" caos_errs "github.com/caos/zitadel/internal/errors" org_model "github.com/caos/zitadel/internal/org/model" usr_model "github.com/caos/zitadel/internal/user/model" @@ -78,7 +78,7 @@ func (l *Login) handleRegisterOrgCheck(w http.ResponseWriter, r *http.Request) { l.renderNextStep(w, r, authRequest) } -func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRequest *model.AuthRequest, formData *registerOrgFormData, err error) { +func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRequest *domain.AuthRequest, formData *registerOrgFormData, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) diff --git a/internal/ui/login/handler/renderer.go b/internal/ui/login/handler/renderer.go index 6dbf8d2dce..486d858a1d 100644 --- a/internal/ui/login/handler/renderer.go +++ b/internal/ui/login/handler/renderer.go @@ -3,6 +3,7 @@ package handler import ( "errors" "fmt" + "github.com/caos/zitadel/internal/v2/domain" "html/template" "net/http" "path" @@ -15,7 +16,6 @@ import ( "github.com/caos/zitadel/internal/auth_request/model" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/i18n" - iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/renderer" ) @@ -153,7 +153,7 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str "hasExternalLogin": func() bool { return false }, - "idpProviderClass": func(stylingType iam_model.IDPStylingType) string { + "idpProviderClass": func(stylingType domain.IDPConfigStylingType) string { return stylingType.GetCSSClass() }, } @@ -167,7 +167,7 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str return r } -func (l *Login) renderNextStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) renderNextStep(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) authReq, err := l.authRepo.AuthRequestByID(r.Context(), authReq.ID, userAgentID) if err != nil { @@ -181,7 +181,7 @@ func (l *Login) renderNextStep(w http.ResponseWriter, r *http.Request, authReq * l.chooseNextStep(w, r, authReq, 0, nil) } -func (l *Login) renderError(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderError(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { if authReq == nil || len(authReq.PossibleSteps) == 0 { l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(err, "APP-OVOiT", "no possible steps")) return @@ -189,54 +189,54 @@ func (l *Login) renderError(w http.ResponseWriter, r *http.Request, authReq *mod l.chooseNextStep(w, r, authReq, 0, err) } -func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, stepNumber int, err error) { +func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, stepNumber int, err error) { switch step := authReq.PossibleSteps[stepNumber].(type) { - case *model.LoginStep: + case *domain.LoginStep: if len(authReq.PossibleSteps) > 1 { l.chooseNextStep(w, r, authReq, 1, err) return } l.renderLogin(w, r, authReq, err) - case *model.SelectUserStep: + case *domain.SelectUserStep: l.renderUserSelection(w, r, authReq, step) - case *model.InitPasswordStep: + case *domain.InitPasswordStep: l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) - case *model.PasswordStep: + case *domain.PasswordStep: l.renderPassword(w, r, authReq, nil) - case *model.PasswordlessStep: + case *domain.PasswordlessStep: l.renderPasswordlessVerification(w, r, authReq, nil) - case *model.MFAVerificationStep: + case *domain.MFAVerificationStep: l.renderMFAVerify(w, r, authReq, step, err) - case *model.RedirectToCallbackStep: + case *domain.RedirectToCallbackStep: if len(authReq.PossibleSteps) > 1 { l.chooseNextStep(w, r, authReq, 1, err) return } l.redirectToCallback(w, r, authReq) - case *model.ChangePasswordStep: + case *domain.ChangePasswordStep: l.renderChangePassword(w, r, authReq, err) - case *model.VerifyEMailStep: + case *domain.VerifyEMailStep: l.renderMailVerification(w, r, authReq, "", err) - case *model.MFAPromptStep: + case *domain.MFAPromptStep: l.renderMFAPrompt(w, r, authReq, step, err) - case *model.InitUserStep: + case *domain.InitUserStep: l.renderInitUser(w, r, authReq, "", "", step.PasswordSet, nil) - case *model.ChangeUsernameStep: + case *domain.ChangeUsernameStep: l.renderChangeUsername(w, r, authReq, nil) - case *model.LinkUsersStep: + case *domain.LinkUsersStep: l.linkUsers(w, r, authReq, err) - case *model.ExternalNotFoundOptionStep: + case *domain.ExternalNotFoundOptionStep: l.renderExternalNotFoundOption(w, r, authReq, err) - case *model.ExternalLoginStep: + case *domain.ExternalLoginStep: l.handleExternalLoginStep(w, r, authReq, step.SelectedIDPConfigID) - case *model.GrantRequiredStep: + case *domain.GrantRequiredStep: l.renderInternalError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-asb43", "Errors.User.GrantRequired")) default: l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-ds3QF", "step no possible")) } } -func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var msg string if err != nil { msg = err.Error() @@ -245,7 +245,7 @@ func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, auth l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplError], data, nil) } -func (l *Login) getUserData(r *http.Request, authReq *model.AuthRequest, title string, errType, errMessage string) userData { +func (l *Login) getUserData(r *http.Request, authReq *domain.AuthRequest, title string, errType, errMessage string) userData { userData := userData{ baseData: l.getBaseData(r, authReq, title, errType, errMessage), profileData: l.getProfileData(authReq), @@ -256,7 +256,7 @@ func (l *Login) getUserData(r *http.Request, authReq *model.AuthRequest, title s return userData } -func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title string, errType, errMessage string) baseData { +func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, title string, errType, errMessage string) baseData { baseData := baseData{ errorData: errorData{ ErrType: errType, @@ -279,7 +279,7 @@ func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title s return baseData } -func (l *Login) getProfileData(authReq *model.AuthRequest) profileData { +func (l *Login) getProfileData(authReq *domain.AuthRequest) profileData { var loginName, displayName string if authReq != nil { loginName = authReq.LoginName @@ -309,7 +309,7 @@ func (l *Login) getThemeMode(r *http.Request) string { return "" //TODO: impl } -func (l *Login) getOrgID(authReq *model.AuthRequest) string { +func (l *Login) getOrgID(authReq *domain.AuthRequest) string { if authReq == nil { return "" } @@ -319,14 +319,14 @@ func (l *Login) getOrgID(authReq *model.AuthRequest) string { return authReq.UserOrgID } -func (l *Login) getOrgName(authReq *model.AuthRequest) string { +func (l *Login) getOrgName(authReq *domain.AuthRequest) string { if authReq == nil { return "" } return authReq.RequestedOrgName } -func getRequestID(authReq *model.AuthRequest, r *http.Request) string { +func getRequestID(authReq *domain.AuthRequest, r *http.Request) string { if authReq != nil { return authReq.ID } @@ -357,8 +357,8 @@ type baseData struct { AuthReqID string CSRF template.HTML Nonce string - LoginPolicy *iam_model.LoginPolicyView - IDPProviders []*iam_model.IDPProviderView + LoginPolicy *domain.LoginPolicy + IDPProviders []*domain.IDPProvider } type errorData struct { @@ -370,8 +370,8 @@ type userData struct { baseData profileData PasswordChecked string - MFAProviders []model.MFAType - SelectedMFAProvider model.MFAType + MFAProviders []domain.MFAType + SelectedMFAProvider domain.MFAType Linking bool } @@ -393,28 +393,28 @@ type passwordData struct { type userSelectionData struct { baseData - Users []model.UserSelection + Users []domain.UserSelection Linking bool } type mfaData struct { baseData profileData - MFAProviders []model.MFAType + MFAProviders []domain.MFAType MFARequired bool } type mfaVerifyData struct { baseData profileData - MFAType model.MFAType + MFAType domain.MFAType otpData } type mfaDoneData struct { baseData profileData - MFAType model.MFAType + MFAType domain.MFAType } type otpData struct { diff --git a/internal/ui/login/handler/select_user_handler.go b/internal/ui/login/handler/select_user_handler.go index 088c963439..c30319d53d 100644 --- a/internal/ui/login/handler/select_user_handler.go +++ b/internal/ui/login/handler/select_user_handler.go @@ -1,10 +1,10 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" http_mw "github.com/caos/zitadel/internal/api/http/middleware" - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -15,7 +15,7 @@ type userSelectionFormData struct { UserID string `schema:"userID"` } -func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, selectionData *model.SelectUserStep) { +func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, selectionData *domain.SelectUserStep) { data := userSelectionData{ baseData: l.getBaseData(r, authReq, "Select User", "", ""), Users: selectionData.Users, diff --git a/internal/ui/login/handler/username_change_handler.go b/internal/ui/login/handler/username_change_handler.go index 690deb3db2..de7bbf60b3 100644 --- a/internal/ui/login/handler/username_change_handler.go +++ b/internal/ui/login/handler/username_change_handler.go @@ -1,9 +1,8 @@ package handler import ( + "github.com/caos/zitadel/internal/v2/domain" "net/http" - - "github.com/caos/zitadel/internal/auth_request/model" ) const ( @@ -15,7 +14,7 @@ type changeUsernameData struct { Username string `schema:"username"` } -func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { +func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var errType, errMessage string if err != nil { errMessage = l.getErrorMessage(r, err) @@ -31,7 +30,7 @@ func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) { l.renderError(w, r, authReq, err) return } - err = l.authRepo.ChangeUsername(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Username) + err = l.command.ChangeUsername(setContext(r.Context(), authReq.UserOrgID), authReq.UserOrgID, authReq.UserID, data.Username) if err != nil { l.renderChangeUsername(w, r, authReq, err) return @@ -39,7 +38,7 @@ func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) { l.renderChangeUsernameDone(w, r, authReq) } -func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { +func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { var errType, errMessage string data := l.getUserData(r, authReq, "Username Change Done", errType, errMessage) l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsernameDone], data, nil) diff --git a/internal/ui/login/static/templates/password_reset_done.html b/internal/ui/login/static/templates/password_reset_done.html index 55a3cc9b57..c8ce9f6105 100644 --- a/internal/ui/login/static/templates/password_reset_done.html +++ b/internal/ui/login/static/templates/password_reset_done.html @@ -12,6 +12,8 @@ + + {{template "error-message" .}}