mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 11:27:33 +00:00
fix: login (#242)
* password in init user only if needed * reactivate user session * set context AuthorizeClientIDSecret * fix qr code for light * fix copy * check user and org active in auth * add org view provider * handle inactive projects * translate error messages
This commit is contained in:
@@ -12,10 +12,12 @@ import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
user_model "github.com/caos/zitadel/internal/user/model"
|
||||
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
type AuthRequestRepo struct {
|
||||
@@ -26,6 +28,7 @@ type AuthRequestRepo struct {
|
||||
UserSessionViewProvider userSessionViewProvider
|
||||
UserViewProvider userViewProvider
|
||||
UserEventProvider userEventProvider
|
||||
OrgViewProvider orgViewProvider
|
||||
|
||||
IdGenerator id.Generator
|
||||
|
||||
@@ -36,17 +39,21 @@ type AuthRequestRepo struct {
|
||||
}
|
||||
|
||||
type userSessionViewProvider interface {
|
||||
UserSessionByIDs(string, string) (*view_model.UserSessionView, error)
|
||||
UserSessionsByAgentID(string) ([]*view_model.UserSessionView, error)
|
||||
UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error)
|
||||
UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error)
|
||||
}
|
||||
type userViewProvider interface {
|
||||
UserByID(string) (*view_model.UserView, error)
|
||||
UserByID(string) (*user_view_model.UserView, error)
|
||||
}
|
||||
|
||||
type userEventProvider interface {
|
||||
UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error)
|
||||
}
|
||||
|
||||
type orgViewProvider interface {
|
||||
OrgByID(string) (*org_view_model.OrgView, error)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) Health(ctx context.Context) error {
|
||||
if err := repo.UserEvents.Health(ctx); err != nil {
|
||||
return err
|
||||
@@ -124,7 +131,7 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID string)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := repo.View.UserByID(userID)
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -169,7 +176,7 @@ func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id string, chec
|
||||
|
||||
func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthRequest, checkLoggedIn bool) ([]model.NextStep, error) {
|
||||
if request == nil {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "request must not be nil")
|
||||
return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "Errors.Internal")
|
||||
}
|
||||
steps := make([]model.NextStep, 0)
|
||||
if !checkLoggedIn && request.Prompt == model.PromptNone {
|
||||
@@ -186,7 +193,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
|
||||
}
|
||||
return steps, nil
|
||||
}
|
||||
user, err := userByID(ctx, repo.UserViewProvider, repo.UserEventProvider, request.UserID)
|
||||
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, request.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -296,7 +303,7 @@ func userSessionsByUserAgentID(provider userSessionViewProvider, agentID string)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return view_model.UserSessionsToModel(session), nil
|
||||
return user_view_model.UserSessionsToModel(session), nil
|
||||
}
|
||||
|
||||
func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eventProvider userEventProvider, agentID string, user *user_model.UserView) (*user_model.UserSessionView, error) {
|
||||
@@ -305,12 +312,12 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
|
||||
if !errors.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
session = &view_model.UserSessionView{}
|
||||
session = &user_view_model.UserSessionView{}
|
||||
}
|
||||
events, err := eventProvider.UserEventsByID(ctx, user.ID, session.Sequence)
|
||||
if err != nil {
|
||||
logging.Log("EVENT-Hse6s").WithError(err).Debug("error retrieving new events")
|
||||
return view_model.UserSessionToModel(session), nil
|
||||
return user_view_model.UserSessionToModel(session), nil
|
||||
}
|
||||
sessionCopy := *session
|
||||
for _, event := range events {
|
||||
@@ -319,19 +326,44 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
|
||||
es_model.UserPasswordCheckFailed,
|
||||
es_model.MfaOtpCheckSucceeded,
|
||||
es_model.MfaOtpCheckFailed,
|
||||
es_model.SignedOut:
|
||||
eventData, err := view_model.UserSessionFromEvent(event)
|
||||
es_model.SignedOut,
|
||||
es_model.UserLocked,
|
||||
es_model.UserDeactivated:
|
||||
eventData, err := user_view_model.UserSessionFromEvent(event)
|
||||
if err != nil {
|
||||
logging.Log("EVENT-sdgT3").WithError(err).Debug("error getting event data")
|
||||
return view_model.UserSessionToModel(session), nil
|
||||
return user_view_model.UserSessionToModel(session), nil
|
||||
}
|
||||
if eventData.UserAgentID != agentID {
|
||||
continue
|
||||
}
|
||||
case es_model.UserRemoved:
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dG2fe", "Errors.User.NotActive")
|
||||
}
|
||||
sessionCopy.AppendEvent(event)
|
||||
}
|
||||
return view_model.UserSessionToModel(&sessionCopy), nil
|
||||
return user_view_model.UserSessionToModel(&sessionCopy), nil
|
||||
}
|
||||
|
||||
func activeUserByID(ctx context.Context, userViewProvider userViewProvider, userEventProvider userEventProvider, orgViewProvider orgViewProvider, userID string) (*user_model.UserView, error) {
|
||||
user, err := userByID(ctx, userViewProvider, userEventProvider, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user.State == user_model.USERSTATE_LOCKED || user.State == user_model.USERSTATE_SUSPEND {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-FJ262", "Errors.User.Locked")
|
||||
}
|
||||
if !(user.State == user_model.USERSTATE_ACTIVE || user.State == user_model.USERSTATE_INITIAL) {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-FJ262", "Errors.User.NotActive")
|
||||
}
|
||||
org, err := orgViewProvider.OrgByID(user.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if org.State != int32(org_model.ORGSTATE_ACTIVE) {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Zws3s", "Errors.User.NotActive")
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider userEventProvider, userID string) (*user_model.UserView, error) {
|
||||
@@ -342,13 +374,13 @@ func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider
|
||||
events, err := eventProvider.UserEventsByID(ctx, userID, user.Sequence)
|
||||
if err != nil {
|
||||
logging.Log("EVENT-dfg42").WithError(err).Debug("error retrieving new events")
|
||||
return view_model.UserToModel(user), nil
|
||||
return user_view_model.UserToModel(user), nil
|
||||
}
|
||||
userCopy := *user
|
||||
for _, event := range events {
|
||||
if err := userCopy.AppendEvent(event); err != nil {
|
||||
return view_model.UserToModel(user), nil
|
||||
return user_view_model.UserToModel(user), nil
|
||||
}
|
||||
}
|
||||
return view_model.UserToModel(&userCopy), nil
|
||||
return user_view_model.UserToModel(&userCopy), nil
|
||||
}
|
||||
|
@@ -13,29 +13,31 @@ import (
|
||||
"github.com/caos/zitadel/internal/auth_request/repository/cache"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
user_model "github.com/caos/zitadel/internal/user/model"
|
||||
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
type mockViewNoUserSession struct{}
|
||||
|
||||
func (m *mockViewNoUserSession) UserSessionByIDs(string, string) (*view_model.UserSessionView, error) {
|
||||
func (m *mockViewNoUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
|
||||
return nil, errors.ThrowNotFound(nil, "id", "user session not found")
|
||||
}
|
||||
|
||||
func (m *mockViewNoUserSession) UserSessionsByAgentID(string) ([]*view_model.UserSessionView, error) {
|
||||
func (m *mockViewNoUserSession) UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error) {
|
||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||
}
|
||||
|
||||
type mockViewErrUserSession struct{}
|
||||
|
||||
func (m *mockViewErrUserSession) UserSessionByIDs(string, string) (*view_model.UserSessionView, error) {
|
||||
func (m *mockViewErrUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
|
||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||
}
|
||||
|
||||
func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*view_model.UserSessionView, error) {
|
||||
func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error) {
|
||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||
}
|
||||
|
||||
@@ -50,17 +52,17 @@ type mockUser struct {
|
||||
LoginName string
|
||||
}
|
||||
|
||||
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*view_model.UserSessionView, error) {
|
||||
return &view_model.UserSessionView{
|
||||
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
|
||||
return &user_view_model.UserSessionView{
|
||||
PasswordVerification: m.PasswordVerification,
|
||||
MfaSoftwareVerification: m.MfaSoftwareVerification,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *mockViewUserSession) UserSessionsByAgentID(string) ([]*view_model.UserSessionView, error) {
|
||||
sessions := make([]*view_model.UserSessionView, len(m.Users))
|
||||
func (m *mockViewUserSession) UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error) {
|
||||
sessions := make([]*user_view_model.UserSessionView, len(m.Users))
|
||||
for i, user := range m.Users {
|
||||
sessions[i] = &view_model.UserSessionView{
|
||||
sessions[i] = &user_view_model.UserSessionView{
|
||||
UserID: user.UserID,
|
||||
LoginName: user.LoginName,
|
||||
}
|
||||
@@ -70,7 +72,7 @@ func (m *mockViewUserSession) UserSessionsByAgentID(string) ([]*view_model.UserS
|
||||
|
||||
type mockViewNoUser struct{}
|
||||
|
||||
func (m *mockViewNoUser) UserByID(string) (*view_model.UserView, error) {
|
||||
func (m *mockViewNoUser) UserByID(string) (*user_view_model.UserView, error) {
|
||||
return nil, errors.ThrowNotFound(nil, "id", "user not found")
|
||||
}
|
||||
|
||||
@@ -102,8 +104,8 @@ type mockViewUser struct {
|
||||
MfaInitSkipped time.Time
|
||||
}
|
||||
|
||||
func (m *mockViewUser) UserByID(string) (*view_model.UserView, error) {
|
||||
return &view_model.UserView{
|
||||
func (m *mockViewUser) UserByID(string) (*user_view_model.UserView, error) {
|
||||
return &user_view_model.UserView{
|
||||
InitRequired: m.InitRequired,
|
||||
PasswordSet: m.PasswordSet,
|
||||
PasswordChangeRequired: m.PasswordChangeRequired,
|
||||
@@ -111,9 +113,26 @@ func (m *mockViewUser) UserByID(string) (*view_model.UserView, error) {
|
||||
OTPState: m.OTPState,
|
||||
MfaMaxSetUp: m.MfaMaxSetUp,
|
||||
MfaInitSkipped: m.MfaInitSkipped,
|
||||
State: int32(user_model.USERSTATE_ACTIVE),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type mockViewOrg struct {
|
||||
State org_model.OrgState
|
||||
}
|
||||
|
||||
func (m *mockViewOrg) OrgByID(string) (*org_view_model.OrgView, error) {
|
||||
return &org_view_model.OrgView{
|
||||
State: int32(m.State),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type mockViewErrOrg struct{}
|
||||
|
||||
func (m *mockViewErrOrg) OrgByID(string) (*org_view_model.OrgView, error) {
|
||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||
}
|
||||
|
||||
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
type fields struct {
|
||||
UserEvents *user_event.UserEventstore
|
||||
@@ -122,6 +141,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
userSessionViewProvider userSessionViewProvider
|
||||
userViewProvider userViewProvider
|
||||
userEventProvider userEventProvider
|
||||
orgViewProvider orgViewProvider
|
||||
PasswordCheckLifeTime time.Duration
|
||||
MfaInitSkippedLifeTime time.Duration
|
||||
MfaSoftwareCheckLifeTime time.Duration
|
||||
@@ -203,7 +223,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"user not not found, not found error",
|
||||
"user not found, not found error",
|
||||
fields{
|
||||
userViewProvider: &mockViewNoUser{},
|
||||
userEventProvider: &mockEventUser{},
|
||||
@@ -212,6 +232,44 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
nil,
|
||||
errors.IsNotFound,
|
||||
},
|
||||
{
|
||||
"user not active, precondition failed error",
|
||||
fields{
|
||||
userViewProvider: &mockViewUser{},
|
||||
userEventProvider: &mockEventUser{
|
||||
&es_models.Event{
|
||||
AggregateType: user_es_model.UserAggregate,
|
||||
Type: user_es_model.UserDeactivated,
|
||||
},
|
||||
},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
nil,
|
||||
errors.IsPreconditionFailed,
|
||||
},
|
||||
{
|
||||
"org error, internal error",
|
||||
fields{
|
||||
userViewProvider: &mockViewUser{},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewErrOrg{},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
nil,
|
||||
errors.IsInternal,
|
||||
},
|
||||
{
|
||||
"org not active, precondition failed error",
|
||||
fields{
|
||||
userViewProvider: &mockViewUser{},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_INACTIVE},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
nil,
|
||||
errors.IsPreconditionFailed,
|
||||
},
|
||||
{
|
||||
"usersession not found, new user session, password step",
|
||||
fields{
|
||||
@@ -220,6 +278,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
PasswordSet: true,
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
[]model.NextStep{&model.PasswordStep{}},
|
||||
@@ -231,6 +290,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
userSessionViewProvider: &mockViewErrUserSession{},
|
||||
userViewProvider: &mockViewUser{},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
nil,
|
||||
@@ -245,6 +305,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
PasswordSet: true,
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
[]model.NextStep{&model.InitUserStep{
|
||||
@@ -258,6 +319,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
userSessionViewProvider: &mockViewUserSession{},
|
||||
userViewProvider: &mockViewUser{},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
[]model.NextStep{&model.InitPasswordStep{}},
|
||||
@@ -271,6 +333,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
PasswordSet: true,
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
},
|
||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
||||
@@ -289,6 +352,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
@@ -312,6 +376,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
@@ -331,6 +396,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
@@ -351,6 +417,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
@@ -371,6 +438,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
@@ -391,6 +459,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: org_model.ORGSTATE_ACTIVE},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
@@ -408,6 +477,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
UserSessionViewProvider: tt.fields.userSessionViewProvider,
|
||||
UserViewProvider: tt.fields.userViewProvider,
|
||||
UserEventProvider: tt.fields.userEventProvider,
|
||||
OrgViewProvider: tt.fields.orgViewProvider,
|
||||
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
|
||||
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
|
||||
MfaSoftwareCheckLifeTime: tt.fields.MfaSoftwareCheckLifeTime,
|
||||
@@ -718,6 +788,24 @@ func Test_userSessionByIDs(t *testing.T) {
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"new user events (user deleted), precondition failed error",
|
||||
args{
|
||||
userProvider: &mockViewUserSession{
|
||||
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
|
||||
},
|
||||
agentID: "agentID",
|
||||
user: &user_model.UserView{ID: "id"},
|
||||
eventProvider: &mockEventUser{
|
||||
&es_models.Event{
|
||||
AggregateType: user_es_model.UserAggregate,
|
||||
Type: user_es_model.UserRemoved,
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
errors.IsPreconditionFailed,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -763,6 +851,7 @@ func Test_userByID(t *testing.T) {
|
||||
},
|
||||
&user_model.UserView{
|
||||
PasswordChangeRequired: true,
|
||||
State: user_model.USERSTATE_ACTIVE,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
@@ -783,6 +872,7 @@ func Test_userByID(t *testing.T) {
|
||||
},
|
||||
&user_model.UserView{
|
||||
PasswordChangeRequired: true,
|
||||
State: user_model.USERSTATE_ACTIVE,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
@@ -807,7 +897,7 @@ func Test_userByID(t *testing.T) {
|
||||
&user_model.UserView{
|
||||
PasswordChangeRequired: false,
|
||||
ChangeDate: time.Now().UTC().Round(1 * time.Second),
|
||||
State: user_model.USERSTATE_INITIAL,
|
||||
State: user_model.USERSTATE_ACTIVE,
|
||||
PasswordChanged: time.Now().UTC().Round(1 * time.Second),
|
||||
},
|
||||
nil,
|
||||
|
@@ -38,7 +38,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
|
||||
return []spooler.Handler{
|
||||
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, orgEvents: repos.OrgEvents},
|
||||
&UserSession{handler: handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount}, userEvents: repos.UserEvents},
|
||||
&Token{handler: handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount}},
|
||||
&Token{handler: handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount}, ProjectEvents: repos.ProjectEvents},
|
||||
&Key{handler: handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount}},
|
||||
&Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}},
|
||||
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
||||
|
@@ -1,21 +1,24 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
project_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
handler
|
||||
ProjectEvents *proj_event.ProjectEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -33,21 +36,44 @@ func (u *Token) EventQuery() (*models.SearchQuery, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventsourcing.UserQuery(sequence), nil
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(user_es_model.UserAggregate, project_es_model.ProjectAggregate).
|
||||
LatestSequenceFilter(sequence), nil
|
||||
}
|
||||
|
||||
func (u *Token) Process(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case es_model.SignedOut:
|
||||
case user_es_model.SignedOut:
|
||||
id, err := agentIDFromSession(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence)
|
||||
return u.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence)
|
||||
case user_es_model.UserLocked,
|
||||
user_es_model.UserDeactivated,
|
||||
user_es_model.UserRemoved:
|
||||
return u.view.DeleteUserTokens(event.AggregateID, event.Sequence)
|
||||
case project_es_model.ApplicationDeactivated,
|
||||
project_es_model.ApplicationRemoved:
|
||||
application, err := applicationFromSession(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return u.view.ProcessedTokenSequence(event.Sequence)
|
||||
return u.view.DeleteApplicationTokens(event.Sequence, application.AppID)
|
||||
case project_es_model.ProjectDeactivated,
|
||||
project_es_model.ProjectRemoved:
|
||||
project, err := u.ProjectEvents.ProjectByID(context.Background(), event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
applicationsIDs := make([]string, 0, len(project.Applications))
|
||||
for _, app := range project.Applications {
|
||||
applicationsIDs = append(applicationsIDs, app.AppID)
|
||||
}
|
||||
return u.view.DeleteApplicationTokens(event.Sequence, applicationsIDs...)
|
||||
default:
|
||||
return u.view.ProcessedTokenSequence(event.Sequence)
|
||||
}
|
||||
@@ -67,3 +93,12 @@ func agentIDFromSession(event *models.Event) (string, error) {
|
||||
}
|
||||
return session["userAgentID"].(string), nil
|
||||
}
|
||||
|
||||
func applicationFromSession(event *models.Event) (*project_es_model.Application, error) {
|
||||
application := new(project_es_model.Application)
|
||||
if err := json.Unmarshal(event.Data, &application); err != nil {
|
||||
logging.Log("EVEN-GRE2q").WithError(err).Error("could not unmarshal event data")
|
||||
return nil, caos_errs.ThrowInternal(nil, "MODEL-Hrw1q", "could not unmarshal data")
|
||||
}
|
||||
return application, nil
|
||||
}
|
||||
|
@@ -67,7 +67,9 @@ func (u *UserSession) Process(event *models.Event) (err error) {
|
||||
return u.updateSession(session, event)
|
||||
case es_model.UserPasswordChanged,
|
||||
es_model.MfaOtpRemoved,
|
||||
es_model.UserProfileChanged:
|
||||
es_model.UserProfileChanged,
|
||||
es_model.UserLocked,
|
||||
es_model.UserDeactivated:
|
||||
sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -78,6 +80,8 @@ func (u *UserSession) Process(event *models.Event) (err error) {
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case es_model.UserRemoved:
|
||||
return u.view.DeleteUserSessions(event.AggregateID, event.Sequence)
|
||||
default:
|
||||
return u.view.ProcessedUserSessionSequence(event.Sequence)
|
||||
}
|
||||
@@ -89,7 +93,6 @@ func (u *UserSession) OnError(event *models.Event, err error) error {
|
||||
}
|
||||
|
||||
func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error {
|
||||
session.Sequence = event.Sequence
|
||||
session.AppendEvent(event)
|
||||
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
|
||||
return err
|
||||
|
@@ -138,6 +138,7 @@ func Start(conf Config, authZ auth.Config, systemDefaults sd.SystemDefaults, aut
|
||||
UserSessionViewProvider: view,
|
||||
UserViewProvider: view,
|
||||
UserEventProvider: user,
|
||||
OrgViewProvider: view,
|
||||
IdGenerator: idGenerator,
|
||||
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
|
||||
MfaInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MfaInitSkip.Duration,
|
||||
|
@@ -59,7 +59,23 @@ func (v *View) DeleteToken(tokenID string, eventSequence uint64) error {
|
||||
}
|
||||
|
||||
func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64) error {
|
||||
err := view.DeleteTokens(v.Db, tokenTable, agentID, userID)
|
||||
err := view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return v.ProcessedTokenSequence(eventSequence)
|
||||
}
|
||||
|
||||
func (v *View) DeleteUserTokens(userID string, eventSequence uint64) error {
|
||||
err := view.DeleteUserTokens(v.Db, tokenTable, userID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return v.ProcessedTokenSequence(eventSequence)
|
||||
}
|
||||
|
||||
func (v *View) DeleteApplicationTokens(eventSequence uint64, ids ...string) error {
|
||||
err := view.DeleteApplicationTokens(v.Db, tokenTable, ids)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@@ -30,8 +30,8 @@ func (v *View) PutUserSession(userSession *model.UserSessionView) error {
|
||||
return v.ProcessedUserSessionSequence(userSession.Sequence)
|
||||
}
|
||||
|
||||
func (v *View) DeleteUserSession(sessionID string, eventSequence uint64) error {
|
||||
err := view.DeleteUserSession(v.Db, userSessionTable, sessionID)
|
||||
func (v *View) DeleteUserSessions(userID string, eventSequence uint64) error {
|
||||
err := view.DeleteUserSessions(v.Db, userSessionTable, userID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user