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
This commit is contained in:
Fabi
2021-02-08 11:30:30 +01:00
committed by GitHub
parent c65331df1a
commit 320679467b
123 changed files with 2949 additions and 1212 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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")

View File

@@ -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,

View File

@@ -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)
}

View File

@@ -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)