mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-04 23:45:07 +00:00
fix(login): improve auth handlers (#7969)
# Which Problems Are Solved During the implementation of #7486 it was noticed, that projections in the `auth` database schema could be blocked. Investigations suggested, that this is due to the use of [GORM](https://gorm.io/index.html) and it's inability to use an existing (sql) transaction. With the improved / simplified handling (see below) there should also be a minimal improvement in performance, resp. reduced database update statements. # How the Problems Are Solved The handlers in `auth` are exchanged to proper (sql) statements and gorm usage is removed for any writing part. To further improve / simplify the handling of the users, a new `auth.users3` table is created, where only attributes are handled, which are not yet available from the `projections.users`, `projections.login_name` and `projections.user_auth_methods` do not provide. This reduces the events handled in that specific handler by a lot. # Additional Changes None # Additional Context relates to #7486
This commit is contained in:
parent
cca342187b
commit
fb162a7d75
27
cmd/setup/26.go
Normal file
27
cmd/setup/26.go
Normal file
@ -0,0 +1,27 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 26.sql
|
||||
authUsers3 string
|
||||
)
|
||||
|
||||
type AuthUsers3 struct {
|
||||
dbClient *database.DB
|
||||
}
|
||||
|
||||
func (mig *AuthUsers3) Execute(ctx context.Context, _ eventstore.Event) error {
|
||||
_, err := mig.dbClient.ExecContext(ctx, authUsers3)
|
||||
return err
|
||||
}
|
||||
|
||||
func (mig *AuthUsers3) String() string {
|
||||
return "26_auth_users3"
|
||||
}
|
16
cmd/setup/26.sql
Normal file
16
cmd/setup/26.sql
Normal file
@ -0,0 +1,16 @@
|
||||
CREATE TABLE IF NOT EXISTS auth.users3 (
|
||||
instance_id TEXT NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
resource_owner TEXT NOT NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
password_set BOOL NULL,
|
||||
password_change TIMESTAMPTZ NULL,
|
||||
last_login TIMESTAMPTZ NULL,
|
||||
init_required BOOL NULL,
|
||||
mfa_init_skipped TIMESTAMPTZ NULL,
|
||||
username_change_required BOOL NULL,
|
||||
passwordless_init_required BOOL NULL,
|
||||
password_init_required BOOL NULL,
|
||||
|
||||
PRIMARY KEY (instance_id, id)
|
||||
)
|
@ -108,6 +108,7 @@ type Steps struct {
|
||||
s23CorrectGlobalUniqueConstraints *CorrectGlobalUniqueConstraints
|
||||
s24AddActorToAuthTokens *AddActorToAuthTokens
|
||||
s25User11AddLowerFieldsToVerifiedEmail *User11AddLowerFieldsToVerifiedEmail
|
||||
s26AuthUsers3 *AuthUsers3
|
||||
}
|
||||
|
||||
func MustNewSteps(v *viper.Viper) *Steps {
|
||||
|
@ -138,6 +138,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
steps.s23CorrectGlobalUniqueConstraints = &CorrectGlobalUniqueConstraints{dbClient: esPusherDBClient}
|
||||
steps.s24AddActorToAuthTokens = &AddActorToAuthTokens{dbClient: queryDBClient}
|
||||
steps.s25User11AddLowerFieldsToVerifiedEmail = &User11AddLowerFieldsToVerifiedEmail{dbClient: esPusherDBClient}
|
||||
steps.s26AuthUsers3 = &AuthUsers3{dbClient: esPusherDBClient}
|
||||
|
||||
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||
logging.OnError(err).Fatal("unable to start projections")
|
||||
@ -175,6 +176,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
steps.s22ActiveInstancesIndex,
|
||||
steps.s23CorrectGlobalUniqueConstraints,
|
||||
steps.s24AddActorToAuthTokens,
|
||||
steps.s26AuthUsers3,
|
||||
} {
|
||||
mustExecuteMigration(ctx, eventstoreClient, step, "migration failed")
|
||||
}
|
||||
|
@ -1517,12 +1517,12 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
|
||||
user_repo.HumanPasswordlessTokenCheckFailedType,
|
||||
user_repo.HumanU2FTokenCheckSucceededType,
|
||||
user_repo.HumanU2FTokenCheckFailedType:
|
||||
eventData, err := user_view_model.UserSessionFromEvent(event)
|
||||
userAgentID, err := user_view_model.UserAgentIDFromEvent(event)
|
||||
if err != nil {
|
||||
logging.WithFields("traceID", tracing.TraceIDFromCtx(ctx)).WithError(err).Debug("error getting event data")
|
||||
return user_view_model.UserSessionToModel(session), nil
|
||||
}
|
||||
if eventData.UserAgentID != agentID {
|
||||
if userAgentID != agentID {
|
||||
continue
|
||||
}
|
||||
case user_repo.UserRemovedType:
|
||||
|
@ -2,6 +2,7 @@ package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
@ -75,11 +76,11 @@ type mockUser struct {
|
||||
|
||||
func (m *mockViewUserSession) UserSessionByIDs(string, string, string) (*user_view_model.UserSessionView, error) {
|
||||
return &user_view_model.UserSessionView{
|
||||
ExternalLoginVerification: m.ExternalLoginVerification,
|
||||
PasswordlessVerification: m.PasswordlessVerification,
|
||||
PasswordVerification: m.PasswordVerification,
|
||||
SecondFactorVerification: m.SecondFactorVerification,
|
||||
MultiFactorVerification: m.MultiFactorVerification,
|
||||
ExternalLoginVerification: sql.NullTime{Time: m.ExternalLoginVerification},
|
||||
PasswordlessVerification: sql.NullTime{Time: m.PasswordlessVerification},
|
||||
PasswordVerification: sql.NullTime{Time: m.PasswordVerification},
|
||||
SecondFactorVerification: sql.NullTime{Time: m.SecondFactorVerification},
|
||||
MultiFactorVerification: sql.NullTime{Time: m.MultiFactorVerification},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -90,7 +91,7 @@ func (m *mockViewUserSession) UserSessionsByAgentID(string, string) ([]*user_vie
|
||||
ResourceOwner: user.ResourceOwner,
|
||||
State: int32(user.SessionState),
|
||||
UserID: user.UserID,
|
||||
LoginName: user.LoginName,
|
||||
LoginName: sql.NullString{String: user.LoginName},
|
||||
}
|
||||
}
|
||||
return sessions, nil
|
||||
|
@ -3,8 +3,6 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
@ -98,50 +96,84 @@ func (t *RefreshToken) Reducers() []handler.AggregateReducer {
|
||||
}
|
||||
|
||||
func (t *RefreshToken) Reduce(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
switch event.Type() {
|
||||
case user.HumanRefreshTokenAddedType:
|
||||
token := new(view_model.RefreshTokenView)
|
||||
err := token.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.view.PutRefreshToken(token)
|
||||
case user.HumanRefreshTokenRenewedType:
|
||||
e := new(user.HumanRefreshTokenRenewedEvent)
|
||||
if err := event.Unmarshal(e); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return zerrors.ThrowInternal(nil, "MODEL-BHn75", "could not unmarshal data")
|
||||
}
|
||||
token, err := t.view.RefreshTokenByID(e.TokenID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = token.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.view.PutRefreshToken(token)
|
||||
case user.HumanRefreshTokenRemovedType:
|
||||
e := new(user.HumanRefreshTokenRemovedEvent)
|
||||
if err := event.Unmarshal(e); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return zerrors.ThrowInternal(nil, "MODEL-Bz653", "could not unmarshal data")
|
||||
}
|
||||
return t.view.DeleteRefreshToken(e.TokenID, event.Aggregate().InstanceID)
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType,
|
||||
user.UserRemovedType:
|
||||
|
||||
return t.view.DeleteUserRefreshTokens(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
case instance.InstanceRemovedEventType:
|
||||
|
||||
return t.view.DeleteInstanceRefreshTokens(event.Aggregate().InstanceID)
|
||||
case org.OrgRemovedEventType:
|
||||
return t.view.DeleteOrgRefreshTokens(event)
|
||||
default:
|
||||
return nil
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user.HumanRefreshTokenAddedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-IoF6j", "reduce.wrong.event.type %s", user.HumanRefreshTokenAddedType)
|
||||
}
|
||||
}), nil
|
||||
columns := []handler.Column{
|
||||
handler.NewCol(view_model.RefreshTokenKeyClientID, e.ClientID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyUserAgentID, e.UserAgentID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyUserID, e.Aggregate().ID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyInstanceID, e.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyTokenID, e.TokenID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyResourceOwner, e.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.RefreshTokenKeyCreationDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.RefreshTokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.RefreshTokenKeySequence, event.Sequence()),
|
||||
handler.NewCol(view_model.RefreshTokenKeyAMR, e.AuthMethodsReferences),
|
||||
handler.NewCol(view_model.RefreshTokenKeyAuthTime, e.AuthTime),
|
||||
handler.NewCol(view_model.RefreshTokenKeyAudience, e.Audience),
|
||||
handler.NewCol(view_model.RefreshTokenKeyExpiration, event.CreatedAt().Add(e.Expiration)),
|
||||
handler.NewCol(view_model.RefreshTokenKeyIdleExpiration, event.CreatedAt().Add(e.IdleExpiration)),
|
||||
handler.NewCol(view_model.RefreshTokenKeyScopes, e.Scopes),
|
||||
handler.NewCol(view_model.RefreshTokenKeyToken, e.TokenID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyActor, view_model.TokenActor{TokenActor: e.Actor}),
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanRefreshTokenRenewedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenRenewedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-AG43hq", "reduce.wrong.event.type %s", user.HumanRefreshTokenRenewedType)
|
||||
}
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.RefreshTokenKeyIdleExpiration, event.CreatedAt().Add(e.IdleExpiration)),
|
||||
handler.NewCol(view_model.RefreshTokenKeyToken, e.RefreshToken),
|
||||
handler.NewCol(view_model.RefreshTokenKeyChangeDate, e.CreatedAt()),
|
||||
handler.NewCol(view_model.RefreshTokenKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyTokenID, e.TokenID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, e.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case user.HumanRefreshTokenRemovedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenRemovedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SFF3t", "reduce.wrong.event.type %s", user.HumanRefreshTokenRemovedType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyTokenID, e.TokenID),
|
||||
},
|
||||
), nil
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType,
|
||||
user.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyUserID, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
@ -150,129 +151,189 @@ func (t *Token) Reducers() []handler.AggregateReducer {
|
||||
}
|
||||
|
||||
func (t *Token) Reduce(event eventstore.Event) (_ *handler.Statement, err error) { //nolint:gocognit
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
switch event.Type() {
|
||||
case user.UserTokenAddedType,
|
||||
user.PersonalAccessTokenAddedType:
|
||||
token := new(view_model.TokenView)
|
||||
err := token.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.view.PutToken(token)
|
||||
case user.UserV1ProfileChangedType,
|
||||
user.HumanProfileChangedType:
|
||||
user := new(view_model.UserView)
|
||||
err := user.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tokens, err := t.view.TokensByUserID(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, token := range tokens {
|
||||
token.PreferredLanguage = user.PreferredLanguage
|
||||
}
|
||||
return t.view.PutTokens(tokens)
|
||||
case user.UserV1SignedOutType,
|
||||
user.HumanSignedOutType:
|
||||
id, err := agentIDFromSession(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.view.DeleteSessionTokens(id, event)
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType,
|
||||
user.UserRemovedType:
|
||||
|
||||
return t.view.DeleteUserTokens(event)
|
||||
case user.UserTokenRemovedType,
|
||||
user.PersonalAccessTokenRemovedType:
|
||||
id, err := tokenIDFromRemovedEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.view.DeleteToken(id, event.Aggregate().InstanceID)
|
||||
case user.HumanRefreshTokenRemovedType:
|
||||
id, err := refreshTokenIDFromRemovedEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.view.DeleteTokensFromRefreshToken(id, event.Aggregate().InstanceID)
|
||||
case project.ApplicationDeactivatedType,
|
||||
project.ApplicationRemovedType:
|
||||
application, err := applicationFromSession(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.view.DeleteApplicationTokens(event, application.AppID)
|
||||
case project.ProjectDeactivatedType,
|
||||
project.ProjectRemovedType:
|
||||
project, err := t.getProjectByID(context.Background(), event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
applicationIDs := make([]string, 0, len(project.Applications))
|
||||
for _, app := range project.Applications {
|
||||
if app.OIDCConfig != nil && app.OIDCConfig.ClientID != "" {
|
||||
applicationIDs = append(applicationIDs, app.OIDCConfig.ClientID)
|
||||
}
|
||||
}
|
||||
|
||||
return t.view.DeleteApplicationTokens(event, applicationIDs...)
|
||||
case instance.InstanceRemovedEventType:
|
||||
return t.view.DeleteInstanceTokens(event)
|
||||
case org.OrgRemovedEventType:
|
||||
// deletes all tokens including PATs, which is expected for now
|
||||
// if there is an undo of the org deletion in the future,
|
||||
// we will need to have a look on how to handle the deleted PATs
|
||||
return t.view.DeleteOrgTokens(event)
|
||||
default:
|
||||
return nil
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user.UserTokenAddedType:
|
||||
e, ok := event.(*user.UserTokenAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-W4tnq", "reduce.wrong.event.type %s", user.UserTokenAddedType)
|
||||
}
|
||||
}), nil
|
||||
return handler.NewCreateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.TokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.TokenKeyID, e.TokenID),
|
||||
handler.NewCol(view_model.TokenKeyCreationDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeySequence, event.Sequence()),
|
||||
handler.NewCol(view_model.TokenKeyApplicationID, e.ApplicationID),
|
||||
handler.NewCol(view_model.TokenKeyUserAgentID, e.UserAgentID),
|
||||
handler.NewCol(view_model.TokenKeyAudience, e.Audience),
|
||||
handler.NewCol(view_model.TokenKeyScopes, e.Scopes),
|
||||
handler.NewCol(view_model.TokenKeyExpiration, e.Expiration),
|
||||
handler.NewCol(view_model.TokenKeyPreferredLanguage, e.PreferredLanguage),
|
||||
handler.NewCol(view_model.TokenKeyRefreshTokenID, e.RefreshTokenID),
|
||||
handler.NewCol(view_model.TokenKeyActor, view_model.TokenActor{TokenActor: e.Actor}),
|
||||
handler.NewCol(view_model.TokenKeyIsPat, false),
|
||||
},
|
||||
), nil
|
||||
case user.PersonalAccessTokenAddedType:
|
||||
e, ok := event.(*user.PersonalAccessTokenAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-zF3rb", "reduce.wrong.event.type %s", user.PersonalAccessTokenAddedType)
|
||||
}
|
||||
return handler.NewCreateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.TokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.TokenKeyID, e.TokenID),
|
||||
handler.NewCol(view_model.TokenKeyCreationDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeySequence, event.Sequence()),
|
||||
handler.NewCol(view_model.TokenKeyScopes, e.Scopes),
|
||||
handler.NewCol(view_model.TokenKeyExpiration, e.Expiration),
|
||||
handler.NewCol(view_model.TokenKeyIsPat, true),
|
||||
},
|
||||
), nil
|
||||
case user.UserV1ProfileChangedType,
|
||||
user.HumanProfileChangedType:
|
||||
e, ok := event.(*user.HumanProfileChangedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-ASF2t", "reduce.wrong.event.type %s", user.HumanProfileChangedType)
|
||||
}
|
||||
if e.PreferredLanguage == nil {
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.TokenKeyPreferredLanguage, gu.Value(e.PreferredLanguage).String()),
|
||||
handler.NewCol(view_model.TokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, e.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyUserID, e.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case user.UserV1SignedOutType,
|
||||
user.HumanSignedOutType:
|
||||
e, ok := event.(*user.HumanSignedOutEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-Wtn2q", "reduce.wrong.event.type %s", user.HumanSignedOutType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCond(view_model.TokenKeyUserAgentID, e.UserAgentID),
|
||||
},
|
||||
), nil
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType,
|
||||
user.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case user.UserTokenRemovedType,
|
||||
user.PersonalAccessTokenRemovedType:
|
||||
var tokenID string
|
||||
switch e := event.(type) {
|
||||
case *user.UserTokenRemovedEvent:
|
||||
tokenID = e.TokenID
|
||||
case *user.PersonalAccessTokenRemovedEvent:
|
||||
tokenID = e.TokenID
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SF3ga", "reduce.wrong.event.type %s", user.UserTokenRemovedType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyID, tokenID),
|
||||
},
|
||||
), nil
|
||||
case user.HumanRefreshTokenRemovedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenRemovedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-Sfe11", "reduce.wrong.event.type %s", user.HumanRefreshTokenRemovedType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyRefreshTokenID, e.TokenID),
|
||||
},
|
||||
), nil
|
||||
case project.ApplicationDeactivatedType,
|
||||
project.ApplicationRemovedType:
|
||||
var applicationID string
|
||||
switch e := event.(type) {
|
||||
case *project.ApplicationDeactivatedEvent:
|
||||
applicationID = e.AppID
|
||||
case *project.ApplicationRemovedEvent:
|
||||
applicationID = e.AppID
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SF3fq", "reduce.wrong.event.type %v", []eventstore.EventType{project.ApplicationDeactivatedType, project.ApplicationRemovedType})
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyApplicationID, applicationID),
|
||||
},
|
||||
), nil
|
||||
case project.ProjectDeactivatedType,
|
||||
project.ProjectRemovedType:
|
||||
project, err := t.getProjectByID(context.Background(), event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applicationIDs := make([]string, 0, len(project.Applications))
|
||||
for _, app := range project.Applications {
|
||||
if app.OIDCConfig != nil && app.OIDCConfig.ClientID != "" {
|
||||
applicationIDs = append(applicationIDs, app.OIDCConfig.ClientID)
|
||||
}
|
||||
}
|
||||
if len(applicationIDs) == 0 {
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewOneOfTextCond(view_model.TokenKeyApplicationID, applicationIDs),
|
||||
},
|
||||
), nil
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
||||
type userAgentIDPayload struct {
|
||||
ID string `json:"userAgentID"`
|
||||
}
|
||||
|
||||
func agentIDFromSession(event eventstore.Event) (string, error) {
|
||||
session := make(map[string]interface{})
|
||||
if err := event.Unmarshal(&session); err != nil {
|
||||
payload := new(userAgentIDPayload)
|
||||
if err := event.Unmarshal(payload); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-sd325", "could not unmarshal data")
|
||||
}
|
||||
agentID, _ := session["userAgentID"].(string)
|
||||
return agentID, nil
|
||||
}
|
||||
|
||||
func applicationFromSession(event eventstore.Event) (*project_es_model.Application, error) {
|
||||
application := new(project_es_model.Application)
|
||||
if err := event.Unmarshal(application); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return nil, zerrors.ThrowInternal(nil, "MODEL-Hrw1q", "could not unmarshal data")
|
||||
}
|
||||
return application, nil
|
||||
}
|
||||
|
||||
func tokenIDFromRemovedEvent(event eventstore.Event) (string, error) {
|
||||
removed := make(map[string]interface{})
|
||||
if err := event.Unmarshal(&removed); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-Sff32", "could not unmarshal data")
|
||||
}
|
||||
return removed["tokenId"].(string), nil
|
||||
}
|
||||
|
||||
func refreshTokenIDFromRemovedEvent(event eventstore.Event) (string, error) {
|
||||
removed := make(map[string]interface{})
|
||||
if err := event.Unmarshal(&removed); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-Dfb3w", "could not unmarshal data")
|
||||
}
|
||||
return removed["tokenId"].(string), nil
|
||||
return payload.ID, nil
|
||||
}
|
||||
|
||||
func (t *Token) getProjectByID(ctx context.Context, projID, instanceID string) (*proj_model.Project, error) {
|
||||
|
@ -4,25 +4,20 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
org_model "github.com/zitadel/zitadel/internal/org/model"
|
||||
org_es_model "github.com/zitadel/zitadel/internal/org/repository/eventsourcing/model"
|
||||
org_view "github.com/zitadel/zitadel/internal/org/repository/view"
|
||||
query2 "github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
user_repo "github.com/zitadel/zitadel/internal/repository/user"
|
||||
usr_view "github.com/zitadel/zitadel/internal/user/repository/view"
|
||||
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
userTable = "auth.users2"
|
||||
userTable = "auth.users3"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@ -58,26 +53,14 @@ func (u *User) Reducers() []handler.AggregateReducer {
|
||||
{
|
||||
Aggregate: user_repo.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: user_repo.HumanOTPSMSAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanOTPSMSRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanOTPEmailAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanOTPEmailRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.MachineAddedEventType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
@ -94,62 +77,14 @@ func (u *User) Reducers() []handler.AggregateReducer {
|
||||
Event: user_repo.HumanRegisteredType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1ProfileChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1EmailChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1EmailVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1PhoneChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1PhoneVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1PhoneRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1AddressChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserDeactivatedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserReactivatedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserLockedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserUnlockedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1MFAOTPAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1MFAOTPVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1MFAOTPRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1MFAInitSkippedType,
|
||||
Reduce: u.ProcessUser,
|
||||
@ -158,86 +93,22 @@ func (u *User) Reducers() []handler.AggregateReducer {
|
||||
Event: user_repo.UserV1PasswordChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanProfileChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanEmailChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanEmailVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanAvatarAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanAvatarRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPhoneChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPhoneVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPhoneRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanAddressChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanMFAOTPAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanMFAOTPVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanMFAOTPRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanU2FTokenAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanU2FTokenVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanU2FTokenRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordlessTokenAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordlessTokenVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordlessTokenRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanMFAInitSkippedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.MachineChangedEventType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
@ -266,14 +137,6 @@ func (u *User) Reducers() []handler.AggregateReducer {
|
||||
Event: user_repo.HumanPasswordlessInitCodeRequestedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserDomainClaimedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserUserNameChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
@ -283,30 +146,6 @@ func (u *User) Reducers() []handler.AggregateReducer {
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.OrgDomainVerifiedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
{
|
||||
Event: org.OrgDomainRemovedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
{
|
||||
Event: org.DomainPolicyAddedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
{
|
||||
Event: org.DomainPolicyChangedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
{
|
||||
Event: org.DomainPolicyRemovedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
{
|
||||
Event: org.OrgDomainPrimarySetEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
{
|
||||
Event: org.OrgRemovedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
@ -327,141 +166,124 @@ func (u *User) Reducers() []handler.AggregateReducer {
|
||||
|
||||
//nolint:gocognit
|
||||
func (u *User) ProcessUser(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
user := new(view_model.UserView)
|
||||
switch event.Type() {
|
||||
case user_repo.UserV1AddedType,
|
||||
user_repo.MachineAddedEventType,
|
||||
user_repo.HumanAddedType,
|
||||
user_repo.UserV1RegisteredType,
|
||||
user_repo.HumanRegisteredType:
|
||||
err = user.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.fillLoginNames(user)
|
||||
case user_repo.UserV1ProfileChangedType,
|
||||
user_repo.UserV1EmailChangedType,
|
||||
user_repo.UserV1EmailVerifiedType,
|
||||
user_repo.UserV1PhoneChangedType,
|
||||
user_repo.UserV1PhoneVerifiedType,
|
||||
user_repo.UserV1PhoneRemovedType,
|
||||
user_repo.UserV1AddressChangedType,
|
||||
user_repo.UserDeactivatedType,
|
||||
user_repo.UserReactivatedType,
|
||||
user_repo.UserLockedType,
|
||||
user_repo.UserUnlockedType,
|
||||
user_repo.UserV1MFAOTPAddedType,
|
||||
user_repo.UserV1MFAOTPVerifiedType,
|
||||
user_repo.UserV1MFAOTPRemovedType,
|
||||
user_repo.UserV1MFAInitSkippedType,
|
||||
user_repo.UserV1PasswordChangedType,
|
||||
user_repo.HumanProfileChangedType,
|
||||
user_repo.HumanEmailChangedType,
|
||||
user_repo.HumanEmailVerifiedType,
|
||||
user_repo.HumanAvatarAddedType,
|
||||
user_repo.HumanAvatarRemovedType,
|
||||
user_repo.HumanPhoneChangedType,
|
||||
user_repo.HumanPhoneVerifiedType,
|
||||
user_repo.HumanPhoneRemovedType,
|
||||
user_repo.HumanAddressChangedType,
|
||||
user_repo.HumanMFAOTPAddedType,
|
||||
user_repo.HumanMFAOTPVerifiedType,
|
||||
user_repo.HumanMFAOTPRemovedType,
|
||||
user_repo.HumanOTPSMSAddedType,
|
||||
user_repo.HumanOTPSMSRemovedType,
|
||||
user_repo.HumanOTPEmailAddedType,
|
||||
user_repo.HumanOTPEmailRemovedType,
|
||||
user_repo.HumanU2FTokenAddedType,
|
||||
user_repo.HumanU2FTokenVerifiedType,
|
||||
user_repo.HumanU2FTokenRemovedType,
|
||||
user_repo.HumanPasswordlessTokenAddedType,
|
||||
user_repo.HumanPasswordlessTokenVerifiedType,
|
||||
user_repo.HumanPasswordlessTokenRemovedType,
|
||||
user_repo.HumanMFAInitSkippedType,
|
||||
user_repo.MachineChangedEventType,
|
||||
user_repo.HumanPasswordChangedType,
|
||||
user_repo.HumanInitialCodeAddedType,
|
||||
user_repo.UserV1InitialCodeAddedType,
|
||||
user_repo.UserV1InitializedCheckSucceededType,
|
||||
user_repo.HumanInitializedCheckSucceededType,
|
||||
user_repo.HumanPasswordlessInitCodeAddedType,
|
||||
user_repo.HumanPasswordlessInitCodeRequestedType:
|
||||
user, err = u.view.UserByID(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
user, err = u.userFromEventstore(event.Aggregate(), user.EventTypes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = user.AppendEvent(event)
|
||||
case user_repo.UserDomainClaimedType,
|
||||
user_repo.UserUserNameChangedType:
|
||||
user, err = u.view.UserByID(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
user, err = u.userFromEventstore(event.Aggregate(), user.EventTypes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = user.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.fillLoginNames(user)
|
||||
case user_repo.UserRemovedType:
|
||||
return u.view.DeleteUser(event.Aggregate().ID, event.Aggregate().InstanceID, event)
|
||||
default:
|
||||
return nil
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user_repo.UserV1AddedType,
|
||||
user_repo.HumanAddedType:
|
||||
e, ok := event.(*user_repo.HumanAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SDAGF", "reduce.wrong.event.type %s", user_repo.HumanAddedType)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return u.setPasswordData(event, e.Secret, e.EncodedHash), nil
|
||||
case user_repo.UserV1RegisteredType,
|
||||
user_repo.HumanRegisteredType:
|
||||
e, ok := event.(*user_repo.HumanRegisteredEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-AS1hz", "reduce.wrong.event.type %s", user_repo.HumanRegisteredType)
|
||||
}
|
||||
return u.view.PutUser(user, event)
|
||||
}), nil
|
||||
return u.setPasswordData(event, e.Secret, e.EncodedHash), nil
|
||||
case user_repo.UserV1PasswordChangedType,
|
||||
user_repo.HumanPasswordChangedType:
|
||||
e, ok := event.(*user_repo.HumanPasswordChangedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-Gd31w", "reduce.wrong.event.type %s", user_repo.HumanPasswordChangedType)
|
||||
}
|
||||
return u.setPasswordData(event, e.Secret, e.EncodedHash), nil
|
||||
case user_repo.UserV1PhoneRemovedType,
|
||||
user_repo.HumanPhoneRemovedType,
|
||||
user_repo.UserV1MFAOTPVerifiedType,
|
||||
user_repo.HumanMFAOTPVerifiedType,
|
||||
user_repo.HumanOTPSMSRemovedType,
|
||||
user_repo.HumanOTPEmailRemovedType,
|
||||
user_repo.HumanU2FTokenVerifiedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyMFAInitSkipped, time.Time{}),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.UserV1MFAInitSkippedType,
|
||||
user_repo.HumanMFAInitSkippedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyMFAInitSkipped, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.UserV1InitialCodeAddedType,
|
||||
user_repo.HumanInitialCodeAddedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyInitRequired, true),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.UserV1InitializedCheckSucceededType,
|
||||
user_repo.HumanInitializedCheckSucceededType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyInitRequired, false),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.HumanPasswordlessInitCodeAddedType,
|
||||
user_repo.HumanPasswordlessInitCodeRequestedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyPasswordlessInitRequired, true),
|
||||
handler.NewCol(view_model.UserKeyPasswordInitRequired, false),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCond(view_model.UserKeyPasswordSet, false),
|
||||
}), nil
|
||||
case user_repo.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
|
||||
userLoginMustBeDomain, primaryDomain, domains, err := u.loginNameInformation(context.Background(), user.ResourceOwner, user.InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
func (u *User) setPasswordData(event eventstore.Event, secret *crypto.CryptoValue, hash string) *handler.Statement {
|
||||
set := secret != nil || hash != ""
|
||||
columns := []handler.Column{
|
||||
handler.NewCol(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.UserKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserKeyPasswordSet, set),
|
||||
handler.NewCol(view_model.UserKeyPasswordInitRequired, !set),
|
||||
handler.NewCol(view_model.UserKeyPasswordChange, event.CreatedAt()),
|
||||
}
|
||||
user.SetLoginNames(userLoginMustBeDomain, domains)
|
||||
user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
|
||||
return nil
|
||||
return handler.NewUpsertStatement(event, columns[0:2], columns)
|
||||
}
|
||||
|
||||
func (u *User) ProcessOrg(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
switch event.Type() {
|
||||
case org.OrgDomainVerifiedEventType,
|
||||
org.OrgDomainRemovedEventType,
|
||||
org.DomainPolicyAddedEventType,
|
||||
org.DomainPolicyChangedEventType,
|
||||
org.DomainPolicyRemovedEventType:
|
||||
return u.fillLoginNamesOnOrgUsers(event)
|
||||
case org.OrgDomainPrimarySetEventType:
|
||||
return u.fillPreferredLoginNamesOnOrgUsers(event)
|
||||
case org.OrgRemovedEventType:
|
||||
return u.view.UpdateOrgOwnerRemovedUsers(event)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (u *User) ProcessInstance(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewStatement(event,
|
||||
func(ex handler.Executer, projectionName string) error {
|
||||
return u.view.DeleteInstanceUsers(event)
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyResourceOwner, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
@ -469,97 +291,16 @@ func (u *User) ProcessInstance(event eventstore.Event) (_ *handler.Statement, er
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) fillLoginNamesOnOrgUsers(event eventstore.Event) error {
|
||||
userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.Aggregate().ResourceOwner, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
func (u *User) ProcessInstance(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
users, err := u.view.UsersByOrgID(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
user.SetLoginNames(userLoginMustBeDomain, domains)
|
||||
}
|
||||
return u.view.PutUsers(users, event)
|
||||
}
|
||||
|
||||
func (u *User) fillPreferredLoginNamesOnOrgUsers(event eventstore.Event) error {
|
||||
userLoginMustBeDomain, primaryDomain, _, err := u.loginNameInformation(context.Background(), event.Aggregate().ResourceOwner, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !userLoginMustBeDomain {
|
||||
return nil
|
||||
}
|
||||
users, err := u.view.UsersByOrgID(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
|
||||
}
|
||||
return u.view.PutUsers(users, event)
|
||||
}
|
||||
|
||||
func (u *User) getOrgByID(ctx context.Context, orgID, instanceID string) (*org_model.Org, error) {
|
||||
query, err := org_view.OrgByIDQuery(orgID, instanceID, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
esOrg := &org_es_model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: orgID,
|
||||
},
|
||||
}
|
||||
events, err := u.es.Filter(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = esOrg.AppendEvents(events...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if esOrg.Sequence == 0 {
|
||||
return nil, zerrors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound")
|
||||
}
|
||||
|
||||
return org_es_model.OrgToModel(esOrg), nil
|
||||
}
|
||||
|
||||
func (u *User) loginNameInformation(ctx context.Context, orgID string, instanceID string) (userLoginMustBeDomain bool, primaryDomain string, domains []*org_model.OrgDomain, err error) {
|
||||
org, err := u.getOrgByID(ctx, orgID, instanceID)
|
||||
if err != nil {
|
||||
return false, "", nil, err
|
||||
}
|
||||
primaryDomain, err = org.GetPrimaryDomain()
|
||||
if err != nil {
|
||||
return false, "", nil, err
|
||||
}
|
||||
if org.DomainPolicy != nil {
|
||||
return org.DomainPolicy.UserLoginMustBeDomain, primaryDomain, org.Domains, nil
|
||||
}
|
||||
policy, err := u.queries.DefaultDomainPolicy(authz.WithInstanceID(ctx, org.InstanceID))
|
||||
if err != nil {
|
||||
return false, "", nil, err
|
||||
}
|
||||
return policy.UserLoginMustBeDomain, primaryDomain, org.Domains, nil
|
||||
}
|
||||
|
||||
func (u *User) userFromEventstore(agg *eventstore.Aggregate, eventTypes []eventstore.EventType) (*view_model.UserView, error) {
|
||||
query, err := usr_view.UserByIDQuery(agg.ID, agg.InstanceID, time.Time{}, eventTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events, err := u.es.Filter(context.Background(), query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user := &view_model.UserView{}
|
||||
for _, e := range events {
|
||||
if err = user.AppendEvent(e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
es_model "github.com/zitadel/zitadel/internal/user/repository/eventsourcing/model"
|
||||
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -187,64 +187,160 @@ func (s *UserSession) Reducers() []handler.AggregateReducer {
|
||||
}
|
||||
}
|
||||
|
||||
func sessionColumns(event eventstore.Event, columns ...handler.Column) ([]handler.Column, error) {
|
||||
userAgent, err := agentIDFromSession(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyUserAgentID, userAgent),
|
||||
handler.NewCol(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.UserSessionKeyCreationDate, handler.OnlySetValueOnInsert(userSessionTable, event.CreatedAt())),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
}, columns...), nil
|
||||
}
|
||||
|
||||
func (u *UserSession) Reduce(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user.UserV1PasswordCheckSucceededType,
|
||||
user.UserV1PasswordCheckFailedType,
|
||||
user.UserV1MFAOTPCheckSucceededType,
|
||||
user.UserV1MFAOTPCheckFailedType,
|
||||
user.UserV1SignedOutType,
|
||||
user.HumanPasswordCheckSucceededType,
|
||||
user.HumanPasswordCheckFailedType,
|
||||
user.UserIDPLoginCheckSucceededType,
|
||||
user.HumanMFAOTPCheckSucceededType,
|
||||
user.HumanPasswordCheckSucceededType:
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1PasswordCheckFailedType,
|
||||
user.HumanPasswordCheckFailedType:
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1MFAOTPCheckSucceededType,
|
||||
user.HumanMFAOTPCheckSucceededType:
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFATypeTOTP),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1MFAOTPCheckFailedType,
|
||||
user.HumanMFAOTPCheckFailedType,
|
||||
user.HumanU2FTokenCheckSucceededType,
|
||||
user.HumanU2FTokenCheckFailedType,
|
||||
user.HumanPasswordlessTokenCheckSucceededType,
|
||||
user.HumanPasswordlessTokenCheckFailedType,
|
||||
user.HumanU2FTokenCheckFailedType:
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1SignedOutType,
|
||||
user.HumanSignedOutType:
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
var session *view_model.UserSessionView
|
||||
eventData, err := view_model.UserSessionFromEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session, err = u.view.UserSessionByIDs(eventData.UserAgentID, event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
session = &view_model.UserSessionView{
|
||||
CreationDate: event.CreatedAt(),
|
||||
ResourceOwner: event.Aggregate().ResourceOwner,
|
||||
UserAgentID: eventData.UserAgentID,
|
||||
UserID: event.Aggregate().ID,
|
||||
State: int32(domain.UserSessionStateActive),
|
||||
InstanceID: event.Aggregate().InstanceID,
|
||||
}
|
||||
}
|
||||
return u.updateSession(session, event)
|
||||
}), nil
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateTerminated),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserIDPLoginCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySelectedIDPConfigID, data.SelectedIDPConfigID),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanU2FTokenCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFATypeU2F),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanPasswordlessTokenCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerificationType, domain.MFATypeU2FUserVerification),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanPasswordlessTokenCheckFailedType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol("passwordless_verification", time.Time{}),
|
||||
handler.NewCol("password_verification", time.Time{}),
|
||||
handler.NewCol("second_factor_verification", time.Time{}),
|
||||
handler.NewCol("second_factor_verification_type", domain.MFALevelNotSetUp),
|
||||
handler.NewCol("multi_factor_verification", time.Time{}),
|
||||
handler.NewCol("multi_factor_verification_type", domain.MFALevelNotSetUp),
|
||||
handler.NewCol("external_login_verification", time.Time{}),
|
||||
handler.NewCol("state", domain.UserSessionStateTerminated),
|
||||
handler.NewCol("change_date", event.CreatedAt()),
|
||||
handler.NewCol("sequence", event.Sequence()),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateTerminated),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond("instance_id", event.Aggregate().InstanceID),
|
||||
handler.NewCond("user_id", event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond("state", domain.UserSessionStateTerminated)),
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
},
|
||||
), nil
|
||||
case user.UserV1PasswordChangedType,
|
||||
@ -256,26 +352,26 @@ func (u *UserSession) Reduce(event eventstore.Event) (_ *handler.Statement, err
|
||||
return handler.NewMultiStatement(event,
|
||||
handler.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol("password_verification", event.CreatedAt()),
|
||||
handler.NewCol("change_date", event.CreatedAt()),
|
||||
handler.NewCol("sequence", event.Sequence()),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond("instance_id", event.Aggregate().InstanceID),
|
||||
handler.NewCond("user_id", event.Aggregate().ID),
|
||||
handler.NewCond("user_agent_id", userAgent),
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserAgentID, userAgent),
|
||||
}),
|
||||
handler.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol("password_verification", time.Time{}),
|
||||
handler.NewCol("change_date", event.CreatedAt()),
|
||||
handler.NewCol("sequence", event.Sequence()),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond("instance_id", event.Aggregate().InstanceID),
|
||||
handler.NewCond("user_id", event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond("user_agent_id", userAgent)),
|
||||
handler.Not(handler.NewCond("state", domain.UserSessionStateTerminated)),
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyUserAgentID, userAgent)),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
}),
|
||||
), nil
|
||||
case user.UserV1MFAOTPRemovedType,
|
||||
@ -283,84 +379,77 @@ func (u *UserSession) Reduce(event eventstore.Event) (_ *handler.Statement, err
|
||||
user.HumanU2FTokenRemovedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol("second_factor_verification", time.Time{}),
|
||||
handler.NewCol("change_date", event.CreatedAt()),
|
||||
handler.NewCol("sequence", event.Sequence()),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond("instance_id", event.Aggregate().InstanceID),
|
||||
handler.NewCond("user_id", event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond("state", domain.UserSessionStateTerminated)),
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
},
|
||||
), nil
|
||||
case user.UserIDPLinkRemovedType,
|
||||
user.UserIDPLinkCascadeRemovedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol("external_login_verification", time.Time{}),
|
||||
handler.NewCol("selected_idp_config_id", ""),
|
||||
handler.NewCol("change_date", event.CreatedAt()),
|
||||
handler.NewCol("sequence", event.Sequence()),
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySelectedIDPConfigID, ""),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond("instance_id", event.Aggregate().InstanceID),
|
||||
handler.NewCond("user_id", event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond("selected_idp_config_id", "")),
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeySelectedIDPConfigID, "")),
|
||||
},
|
||||
), nil
|
||||
case user.HumanPasswordlessTokenRemovedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol("passwordless_verification", time.Time{}),
|
||||
handler.NewCol("multi_factor_verification", time.Time{}),
|
||||
handler.NewCol("change_date", event.CreatedAt()),
|
||||
handler.NewCol("sequence", event.Sequence()),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond("instance_id", event.Aggregate().InstanceID),
|
||||
handler.NewCond("user_id", event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond("state", domain.UserSessionStateTerminated)),
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
},
|
||||
), nil
|
||||
case user.UserRemovedType:
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
return u.view.DeleteUserSessions(event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
}), nil
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case user.HumanRegisteredType:
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
eventData, err := view_model.UserSessionFromEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session := &view_model.UserSessionView{
|
||||
CreationDate: event.CreatedAt(),
|
||||
ResourceOwner: event.Aggregate().ResourceOwner,
|
||||
UserAgentID: eventData.UserAgentID,
|
||||
UserID: event.Aggregate().ID,
|
||||
State: int32(domain.UserSessionStateActive),
|
||||
InstanceID: event.Aggregate().InstanceID,
|
||||
PasswordVerification: event.CreatedAt(),
|
||||
}
|
||||
return u.updateSession(session, event)
|
||||
}), nil
|
||||
columns, err := sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, event.CreatedAt()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewCreateStatement(event,
|
||||
columns,
|
||||
), nil
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
return u.view.DeleteInstanceUserSessions(event.Aggregate().InstanceID)
|
||||
}), nil
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
return u.view.DeleteOrgUserSessions(event)
|
||||
}), nil
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
return nil
|
||||
}), nil
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserSession) updateSession(session *view_model.UserSessionView, event eventstore.Event) error {
|
||||
if err := session.AppendEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
return u.view.PutUserSession(session)
|
||||
}
|
||||
|
@ -4,13 +4,10 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
user_model "github.com/zitadel/zitadel/internal/user/model"
|
||||
usr_view "github.com/zitadel/zitadel/internal/user/repository/view"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -29,54 +26,6 @@ func (v *View) SearchRefreshTokens(request *user_model.RefreshTokenSearchRequest
|
||||
return usr_view.SearchRefreshTokens(v.Db, refreshTokenTable, request)
|
||||
}
|
||||
|
||||
func (v *View) PutRefreshToken(token *model.RefreshTokenView) error {
|
||||
return usr_view.PutRefreshToken(v.Db, refreshTokenTable, token)
|
||||
}
|
||||
|
||||
func (v *View) PutRefreshTokens(token []*model.RefreshTokenView) error {
|
||||
return usr_view.PutRefreshTokens(v.Db, refreshTokenTable, token...)
|
||||
}
|
||||
|
||||
func (v *View) DeleteRefreshToken(tokenID, instanceID string) error {
|
||||
err := usr_view.DeleteRefreshToken(v.Db, refreshTokenTable, tokenID, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteUserRefreshTokens(userID, instanceID string) error {
|
||||
err := usr_view.DeleteUserRefreshTokens(v.Db, refreshTokenTable, userID, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteApplicationRefreshTokens(event *models.Event, ids ...string) error {
|
||||
err := usr_view.DeleteApplicationTokens(v.Db, refreshTokenTable, event.InstanceID, ids)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteInstanceRefreshTokens(instanceID string) error {
|
||||
err := usr_view.DeleteInstanceRefreshTokens(v.Db, refreshTokenTable, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteOrgRefreshTokens(event eventstore.Event) error {
|
||||
err := usr_view.DeleteOrgRefreshTokens(v.Db, refreshTokenTable, event.Aggregate().InstanceID, event.Aggregate().ResourceOwner)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) GetLatestRefreshTokenSequence(ctx context.Context) (_ *query.CurrentState, err error) {
|
||||
q := &query.CurrentStateSearchQueries{
|
||||
Queries: make([]query.SearchQuery, 2),
|
||||
|
@ -3,12 +3,10 @@ package view
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
usr_view "github.com/zitadel/zitadel/internal/user/repository/view"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -23,70 +21,6 @@ func (v *View) TokensByUserID(userID, instanceID string) ([]*model.TokenView, er
|
||||
return usr_view.TokensByUserID(v.Db, tokenTable, userID, instanceID)
|
||||
}
|
||||
|
||||
func (v *View) PutToken(token *model.TokenView) error {
|
||||
return usr_view.PutToken(v.Db, tokenTable, token)
|
||||
}
|
||||
|
||||
func (v *View) PutTokens(token []*model.TokenView) error {
|
||||
return usr_view.PutTokens(v.Db, tokenTable, token...)
|
||||
}
|
||||
|
||||
func (v *View) DeleteToken(tokenID, instanceID string) error {
|
||||
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteSessionTokens(agentID string, event eventstore.Event) error {
|
||||
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteUserTokens(event eventstore.Event) error {
|
||||
err := usr_view.DeleteUserTokens(v.Db, tokenTable, event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteApplicationTokens(event eventstore.Event, ids ...string) error {
|
||||
err := usr_view.DeleteApplicationTokens(v.Db, tokenTable, event.Aggregate().InstanceID, ids)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteTokensFromRefreshToken(refreshTokenID, instanceID string) error {
|
||||
err := usr_view.DeleteTokensFromRefreshToken(v.Db, tokenTable, refreshTokenID, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteInstanceTokens(event eventstore.Event) error {
|
||||
err := usr_view.DeleteInstanceTokens(v.Db, tokenTable, event.Aggregate().InstanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteOrgTokens(event eventstore.Event) error {
|
||||
err := usr_view.DeleteOrgTokens(v.Db, tokenTable, event.Aggregate().InstanceID, event.Aggregate().ResourceOwner)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) GetLatestTokenSequence(ctx context.Context, instanceID string) (_ *query.CurrentState, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
usr_model "github.com/zitadel/zitadel/internal/user/model"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view"
|
||||
@ -14,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
userTable = "auth.users2"
|
||||
userTable = "auth.users3"
|
||||
)
|
||||
|
||||
func (v *View) UserByID(userID, instanceID string) (*model.UserView, error) {
|
||||
@ -142,42 +141,6 @@ func (v *View) userByID(ctx context.Context, instanceID string, queries ...query
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (v *View) UsersByOrgID(orgID, instanceID string) ([]*model.UserView, error) {
|
||||
return view.UsersByOrgID(v.Db, userTable, orgID, instanceID)
|
||||
}
|
||||
|
||||
func (v *View) PutUser(user *model.UserView, event eventstore.Event) error {
|
||||
return view.PutUser(v.Db, userTable, user)
|
||||
}
|
||||
|
||||
func (v *View) PutUsers(users []*model.UserView, event eventstore.Event) error {
|
||||
return view.PutUsers(v.Db, userTable, users...)
|
||||
}
|
||||
|
||||
func (v *View) DeleteUser(userID, instanceID string, event eventstore.Event) error {
|
||||
err := view.DeleteUser(v.Db, userTable, userID, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteInstanceUsers(event eventstore.Event) error {
|
||||
err := view.DeleteInstanceUsers(v.Db, userTable, event.Aggregate().InstanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) UpdateOrgOwnerRemovedUsers(event eventstore.Event) error {
|
||||
err := view.UpdateOrgOwnerRemovedUsers(v.Db, userTable, event.Aggregate().InstanceID, event.Aggregate().ID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) GetLatestUserSequence(ctx context.Context, instanceID string) (_ *query.CurrentState, err error) {
|
||||
q := &query.CurrentStateSearchQueries{
|
||||
Queries: make([]query.SearchQuery, 2),
|
||||
|
@ -3,11 +3,9 @@ package view
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -22,34 +20,6 @@ func (v *View) UserSessionsByAgentID(agentID, instanceID string) ([]*model.UserS
|
||||
return view.UserSessionsByAgentID(v.client, agentID, instanceID)
|
||||
}
|
||||
|
||||
func (v *View) PutUserSession(userSession *model.UserSessionView) error {
|
||||
return view.PutUserSession(v.Db, userSessionTable, userSession)
|
||||
}
|
||||
|
||||
func (v *View) DeleteUserSessions(userID, instanceID string) error {
|
||||
err := view.DeleteUserSessions(v.Db, userSessionTable, userID, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteInstanceUserSessions(instanceID string) error {
|
||||
err := view.DeleteInstanceUserSessions(v.Db, userSessionTable, instanceID)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteOrgUserSessions(event eventstore.Event) error {
|
||||
err := view.DeleteOrgUserSessions(v.Db, userSessionTable, event.Aggregate().InstanceID, event.Aggregate().ResourceOwner)
|
||||
if err != nil && !zerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) GetLatestUserSessionSequence(ctx context.Context, instanceID string) (_ *query.CurrentState, err error) {
|
||||
q := &query.CurrentStateSearchQueries{
|
||||
Queries: make([]query.SearchQuery, 2),
|
||||
|
@ -565,6 +565,13 @@ func Not(condition Condition) Condition {
|
||||
}
|
||||
}
|
||||
|
||||
// NewOneOfTextCond returns a Condition that checks if the column that stores a text is one of the given values
|
||||
func NewOneOfTextCond(column string, values []string) Condition {
|
||||
return func(param string) (string, []any) {
|
||||
return column + " = ANY(" + param + ")", []any{database.TextArray[string](values)}
|
||||
}
|
||||
}
|
||||
|
||||
type Executer interface {
|
||||
Exec(string, ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
@ -13,13 +13,24 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
RefreshTokenKeyTokenID = "id"
|
||||
RefreshTokenKeyUserID = "user_id"
|
||||
RefreshTokenKeyApplicationID = "application_id"
|
||||
RefreshTokenKeyUserAgentID = "user_agent_id"
|
||||
RefreshTokenKeyExpiration = "expiration"
|
||||
RefreshTokenKeyResourceOwner = "resource_owner"
|
||||
RefreshTokenKeyInstanceID = "instance_id"
|
||||
RefreshTokenKeyTokenID = "id"
|
||||
RefreshTokenKeyUserID = "user_id"
|
||||
RefreshTokenKeyApplicationID = "application_id"
|
||||
RefreshTokenKeyUserAgentID = "user_agent_id"
|
||||
RefreshTokenKeyExpiration = "expiration"
|
||||
RefreshTokenKeyResourceOwner = "resource_owner"
|
||||
RefreshTokenKeyInstanceID = "instance_id"
|
||||
RefreshTokenKeyCreationDate = "creation_date"
|
||||
RefreshTokenKeyChangeDate = "change_date"
|
||||
RefreshTokenKeySequence = "sequence"
|
||||
RefreshTokenKeyActor = "actor"
|
||||
RefreshTokenKeyAMR = "amr"
|
||||
RefreshTokenKeyAuthTime = "auth_time"
|
||||
RefreshTokenKeyAudience = "audience"
|
||||
RefreshTokenKeyClientID = "client_id"
|
||||
RefreshTokenKeyIdleExpiration = "idle_expiration"
|
||||
RefreshTokenKeyScopes = "scopes"
|
||||
RefreshTokenKeyToken = "token"
|
||||
)
|
||||
|
||||
type RefreshTokenView struct {
|
||||
@ -72,6 +83,7 @@ func RefreshTokenViewToModel(token *RefreshTokenView) *usr_model.RefreshTokenVie
|
||||
}
|
||||
|
||||
func (t *RefreshTokenView) AppendEventIfMyRefreshToken(event eventstore.Event) (err error) {
|
||||
// in case anything needs to be change here check if the Reduce function needs the change as well
|
||||
view := new(RefreshTokenView)
|
||||
switch event.Type() {
|
||||
case user_repo.HumanRefreshTokenAddedType:
|
||||
@ -101,6 +113,7 @@ func (t *RefreshTokenView) AppendEventIfMyRefreshToken(event eventstore.Event) (
|
||||
}
|
||||
|
||||
func (t *RefreshTokenView) AppendEvent(event eventstore.Event) error {
|
||||
// in case anything needs to be change here check if the Reduce function needs the change as well
|
||||
t.ChangeDate = event.CreatedAt()
|
||||
t.Sequence = event.Sequence()
|
||||
switch event.Type() {
|
||||
@ -123,7 +136,7 @@ func (t *RefreshTokenView) setRootData(event eventstore.Event) {
|
||||
func (t *RefreshTokenView) appendAddedEvent(event eventstore.Event) error {
|
||||
e := new(user_repo.HumanRefreshTokenAddedEvent)
|
||||
if err := event.Unmarshal(e); err != nil {
|
||||
logging.Log("EVEN-Dbb31").WithError(err).Error("could not unmarshal event data")
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return zerrors.ThrowInternal(err, "MODEL-Bbr42", "could not unmarshal event")
|
||||
}
|
||||
t.ID = e.TokenID
|
||||
@ -144,7 +157,7 @@ func (t *RefreshTokenView) appendAddedEvent(event eventstore.Event) error {
|
||||
func (t *RefreshTokenView) appendRenewedEvent(event eventstore.Event) error {
|
||||
e := new(user_repo.HumanRefreshTokenRenewedEvent)
|
||||
if err := event.Unmarshal(e); err != nil {
|
||||
logging.Log("EVEN-Vbbn2").WithError(err).Error("could not unmarshal event data")
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return zerrors.ThrowInternal(err, "MODEL-Bbrn4", "could not unmarshal event")
|
||||
}
|
||||
t.ID = e.TokenID
|
||||
|
@ -16,14 +16,23 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
TokenKeyTokenID = "id"
|
||||
TokenKeyUserID = "user_id"
|
||||
TokenKeyRefreshTokenID = "refresh_token_id"
|
||||
TokenKeyApplicationID = "application_id"
|
||||
TokenKeyUserAgentID = "user_agent_id"
|
||||
TokenKeyExpiration = "expiration"
|
||||
TokenKeyResourceOwner = "resource_owner"
|
||||
TokenKeyInstanceID = "instance_id"
|
||||
TokenKeyTokenID = "id"
|
||||
TokenKeyUserID = "user_id"
|
||||
TokenKeyRefreshTokenID = "refresh_token_id"
|
||||
TokenKeyApplicationID = "application_id"
|
||||
TokenKeyUserAgentID = "user_agent_id"
|
||||
TokenKeyExpiration = "expiration"
|
||||
TokenKeyResourceOwner = "resource_owner"
|
||||
TokenKeyInstanceID = "instance_id"
|
||||
TokenKeyCreationDate = "creation_date"
|
||||
TokenKeyChangeDate = "change_date"
|
||||
TokenKeySequence = "sequence"
|
||||
TokenKeyActor = "actor"
|
||||
TokenKeyID = "id"
|
||||
TokenKeyAudience = "audience"
|
||||
TokenKeyPreferredLanguage = "preferred_language"
|
||||
TokenKeyScopes = "scopes"
|
||||
TokenKeyIsPat = "is_pat"
|
||||
)
|
||||
|
||||
type TokenView struct {
|
||||
@ -100,6 +109,7 @@ func TokenViewToModel(token *TokenView) *usr_model.TokenView {
|
||||
}
|
||||
|
||||
func (t *TokenView) AppendEventIfMyToken(event eventstore.Event) (err error) {
|
||||
// in case anything needs to be change here check if the Reduce function needs the change as well
|
||||
view := new(TokenView)
|
||||
switch event.Type() {
|
||||
case user_repo.UserTokenAddedType,
|
||||
@ -112,7 +122,7 @@ func (t *TokenView) AppendEventIfMyToken(event eventstore.Event) (err error) {
|
||||
return t.appendRefreshTokenRemoved(event)
|
||||
case user_repo.UserV1SignedOutType,
|
||||
user_repo.HumanSignedOutType:
|
||||
id, err := agentIDFromSession(event)
|
||||
id, err := UserAgentIDFromEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -146,6 +156,7 @@ func (t *TokenView) AppendEventIfMyToken(event eventstore.Event) (err error) {
|
||||
}
|
||||
|
||||
func (t *TokenView) AppendEvent(event eventstore.Event) error {
|
||||
// in case anything needs to be change here check if the Reduce function needs the change as well
|
||||
t.ChangeDate = event.CreatedAt()
|
||||
t.Sequence = event.Sequence()
|
||||
switch event.Type() {
|
||||
@ -170,49 +181,40 @@ func (t *TokenView) setRootData(event eventstore.Event) {
|
||||
|
||||
func (t *TokenView) setData(event eventstore.Event) error {
|
||||
if err := event.Unmarshal(t); err != nil {
|
||||
logging.Log("EVEN-3Gm9s").WithError(err).Error("could not unmarshal event data")
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return zerrors.ThrowInternal(err, "MODEL-5Gms9", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func agentIDFromSession(event eventstore.Event) (string, error) {
|
||||
session := make(map[string]interface{})
|
||||
if err := event.Unmarshal(&session); err != nil {
|
||||
logging.Log("EVEN-Ghgt3").WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-GBf32", "could not unmarshal data")
|
||||
}
|
||||
return session["userAgentID"].(string), nil
|
||||
}
|
||||
|
||||
func (t *TokenView) appendTokenRemoved(event eventstore.Event) error {
|
||||
token, err := eventToMap(event)
|
||||
tokenID, err := tokenIDFromEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if token["tokenId"] == t.ID {
|
||||
if tokenID == t.ID {
|
||||
t.Deactivated = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TokenView) appendRefreshTokenRemoved(event eventstore.Event) error {
|
||||
refreshToken, err := eventToMap(event)
|
||||
tokenID, err := tokenIDFromEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if refreshToken["tokenId"] == t.RefreshTokenID {
|
||||
if tokenID == t.RefreshTokenID {
|
||||
t.Deactivated = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TokenView) appendPATRemoved(event eventstore.Event) error {
|
||||
pat, err := eventToMap(event)
|
||||
tokenID, err := tokenIDFromEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pat["tokenId"] == t.ID && t.IsPAT {
|
||||
if tokenID == t.ID && t.IsPAT {
|
||||
t.Deactivated = true
|
||||
}
|
||||
return nil
|
||||
@ -235,11 +237,15 @@ func (t *TokenView) GetRelevantEventTypes() []eventstore.EventType {
|
||||
}
|
||||
}
|
||||
|
||||
func eventToMap(event eventstore.Event) (map[string]interface{}, error) {
|
||||
m := make(map[string]interface{})
|
||||
if err := event.Unmarshal(&m); err != nil {
|
||||
logging.Log("EVEN-Dbffe").WithError(err).Error("could not unmarshal event data")
|
||||
return nil, zerrors.ThrowInternal(nil, "MODEL-SDAfw", "could not unmarshal data")
|
||||
}
|
||||
return m, nil
|
||||
type tokenIDPayload struct {
|
||||
ID string `json:"tokenId"`
|
||||
}
|
||||
|
||||
func tokenIDFromEvent(event eventstore.Event) (string, error) {
|
||||
m := new(tokenIDPayload)
|
||||
if err := event.Unmarshal(&m); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-SDAfw", "could not unmarshal data")
|
||||
}
|
||||
return m.ID, nil
|
||||
}
|
||||
|
@ -18,27 +18,27 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
UserKeyUserID = "id"
|
||||
UserKeyUserName = "user_name"
|
||||
UserKeyFirstName = "first_name"
|
||||
UserKeyLastName = "last_name"
|
||||
UserKeyNickName = "nick_name"
|
||||
UserKeyDisplayName = "display_name"
|
||||
UserKeyEmail = "email"
|
||||
UserKeyState = "user_state"
|
||||
UserKeyResourceOwner = "resource_owner"
|
||||
UserKeyLoginNames = "login_names"
|
||||
UserKeyPreferredLoginName = "preferred_login_name"
|
||||
UserKeyType = "user_type"
|
||||
UserKeyInstanceID = "instance_id"
|
||||
UserKeyOwnerRemoved = "owner_removed"
|
||||
)
|
||||
|
||||
type userType string
|
||||
|
||||
const (
|
||||
userTypeHuman = "human"
|
||||
userTypeMachine = "machine"
|
||||
UserKeyUserID = "id"
|
||||
UserKeyUserName = "user_name"
|
||||
UserKeyFirstName = "first_name"
|
||||
UserKeyLastName = "last_name"
|
||||
UserKeyNickName = "nick_name"
|
||||
UserKeyDisplayName = "display_name"
|
||||
UserKeyEmail = "email"
|
||||
UserKeyState = "user_state"
|
||||
UserKeyResourceOwner = "resource_owner"
|
||||
UserKeyLoginNames = "login_names"
|
||||
UserKeyPreferredLoginName = "preferred_login_name"
|
||||
UserKeyType = "user_type"
|
||||
UserKeyInstanceID = "instance_id"
|
||||
UserKeyOwnerRemoved = "owner_removed"
|
||||
UserKeyPasswordSet = "password_set"
|
||||
UserKeyPasswordInitRequired = "password_init_required"
|
||||
UserKeyPasswordChange = "password_change"
|
||||
UserKeyInitRequired = "init_required"
|
||||
UserKeyPasswordlessInitRequired = "passwordless_init_required"
|
||||
UserKeyMFAInitSkipped = "mfa_init_skipped"
|
||||
UserKeyChangeDate = "change_date"
|
||||
)
|
||||
|
||||
type UserView struct {
|
||||
@ -51,7 +51,6 @@ type UserView struct {
|
||||
LoginNames database.TextArray[string] `json:"-" gorm:"column:login_names"`
|
||||
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
Type userType `json:"-" gorm:"column:user_type"`
|
||||
UserName string `json:"userName" gorm:"column:user_name"`
|
||||
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
||||
*MachineView
|
||||
@ -236,13 +235,13 @@ func (u *UserView) SetLoginNames(userLoginMustBeDomain bool, domains []*org_mode
|
||||
}
|
||||
|
||||
func (u *UserView) AppendEvent(event eventstore.Event) (err error) {
|
||||
// in case anything needs to be change here check if the Reduce function needs the change as well
|
||||
u.ChangeDate = event.CreatedAt()
|
||||
u.Sequence = event.Sequence()
|
||||
switch event.Type() {
|
||||
case user.MachineAddedEventType:
|
||||
u.CreationDate = event.CreatedAt()
|
||||
u.setRootData(event)
|
||||
u.Type = userTypeMachine
|
||||
err = u.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -253,7 +252,6 @@ func (u *UserView) AppendEvent(event eventstore.Event) (err error) {
|
||||
user.HumanAddedType:
|
||||
u.CreationDate = event.CreatedAt()
|
||||
u.setRootData(event)
|
||||
u.Type = userTypeHuman
|
||||
err = u.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -396,7 +394,7 @@ func (u *UserView) setData(event eventstore.Event) error {
|
||||
func (u *UserView) setPasswordData(event eventstore.Event) error {
|
||||
password := new(es_model.Password)
|
||||
if err := event.Unmarshal(password); err != nil {
|
||||
logging.Log("MODEL-sdw4r").WithError(err).Error("could not unmarshal event data")
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return zerrors.ThrowInternal(nil, "MODEL-6jhsw", "could not unmarshal data")
|
||||
}
|
||||
u.PasswordSet = password.Secret != nil || password.EncodedHash != ""
|
||||
|
@ -1,6 +1,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
@ -14,12 +15,23 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
UserSessionKeyUserAgentID = "user_agent_id"
|
||||
UserSessionKeyUserID = "user_id"
|
||||
UserSessionKeyState = "state"
|
||||
UserSessionKeyResourceOwner = "resource_owner"
|
||||
UserSessionKeyInstanceID = "instance_id"
|
||||
UserSessionKeyOwnerRemoved = "owner_removed"
|
||||
UserSessionKeyUserAgentID = "user_agent_id"
|
||||
UserSessionKeyUserID = "user_id"
|
||||
UserSessionKeyState = "state"
|
||||
UserSessionKeyResourceOwner = "resource_owner"
|
||||
UserSessionKeyInstanceID = "instance_id"
|
||||
UserSessionKeyOwnerRemoved = "owner_removed"
|
||||
UserSessionKeyCreationDate = "creation_date"
|
||||
UserSessionKeyChangeDate = "change_date"
|
||||
UserSessionKeySequence = "sequence"
|
||||
UserSessionKeyPasswordVerification = "password_verification"
|
||||
UserSessionKeySecondFactorVerification = "second_factor_verification"
|
||||
UserSessionKeySecondFactorVerificationType = "second_factor_verification_type"
|
||||
UserSessionKeyMultiFactorVerification = "multi_factor_verification"
|
||||
UserSessionKeyMultiFactorVerificationType = "multi_factor_verification_type"
|
||||
UserSessionKeyPasswordlessVerification = "passwordless_verification"
|
||||
UserSessionKeyExternalLoginVerification = "external_login_verification"
|
||||
UserSessionKeySelectedIDPConfigID = "selected_idp_config_id"
|
||||
)
|
||||
|
||||
type UserSessionView struct {
|
||||
@ -33,29 +45,33 @@ type UserSessionView struct {
|
||||
// are not projected in the user session handler anymore
|
||||
// and are therefore annotated with a `gorm:"-"`.
|
||||
// They will be read from the corresponding projection directly.
|
||||
UserName string `json:"-" gorm:"-"`
|
||||
LoginName string `json:"-" gorm:"-"`
|
||||
DisplayName string `json:"-" gorm:"-"`
|
||||
AvatarKey string `json:"-" gorm:"-"`
|
||||
SelectedIDPConfigID string `json:"selectedIDPConfigID" gorm:"column:selected_idp_config_id"`
|
||||
PasswordVerification time.Time `json:"-" gorm:"column:password_verification"`
|
||||
PasswordlessVerification time.Time `json:"-" gorm:"column:passwordless_verification"`
|
||||
ExternalLoginVerification time.Time `json:"-" gorm:"column:external_login_verification"`
|
||||
SecondFactorVerification time.Time `json:"-" gorm:"column:second_factor_verification"`
|
||||
SecondFactorVerificationType int32 `json:"-" gorm:"column:second_factor_verification_type"`
|
||||
MultiFactorVerification time.Time `json:"-" gorm:"column:multi_factor_verification"`
|
||||
MultiFactorVerificationType int32 `json:"-" gorm:"column:multi_factor_verification_type"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
||||
UserName sql.NullString `json:"-" gorm:"-"`
|
||||
LoginName sql.NullString `json:"-" gorm:"-"`
|
||||
DisplayName sql.NullString `json:"-" gorm:"-"`
|
||||
AvatarKey sql.NullString `json:"-" gorm:"-"`
|
||||
SelectedIDPConfigID sql.NullString `json:"selectedIDPConfigID" gorm:"column:selected_idp_config_id"`
|
||||
PasswordVerification sql.NullTime `json:"-" gorm:"column:password_verification"`
|
||||
PasswordlessVerification sql.NullTime `json:"-" gorm:"column:passwordless_verification"`
|
||||
ExternalLoginVerification sql.NullTime `json:"-" gorm:"column:external_login_verification"`
|
||||
SecondFactorVerification sql.NullTime `json:"-" gorm:"column:second_factor_verification"`
|
||||
SecondFactorVerificationType sql.NullInt32 `json:"-" gorm:"column:second_factor_verification_type"`
|
||||
MultiFactorVerification sql.NullTime `json:"-" gorm:"column:multi_factor_verification"`
|
||||
MultiFactorVerificationType sql.NullInt32 `json:"-" gorm:"column:multi_factor_verification_type"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
||||
}
|
||||
|
||||
func UserSessionFromEvent(event eventstore.Event) (*UserSessionView, error) {
|
||||
v := new(UserSessionView)
|
||||
if err := event.Unmarshal(v); err != nil {
|
||||
logging.Log("EVEN-lso9e").WithError(err).Error("could not unmarshal event data")
|
||||
return nil, zerrors.ThrowInternal(nil, "MODEL-sd325", "could not unmarshal data")
|
||||
type userAgentIDPayload struct {
|
||||
ID string `json:"userAgentID"`
|
||||
}
|
||||
|
||||
func UserAgentIDFromEvent(event eventstore.Event) (string, error) {
|
||||
payload := new(userAgentIDPayload)
|
||||
if err := event.Unmarshal(payload); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-HJwk9", "could not unmarshal data")
|
||||
}
|
||||
return v, nil
|
||||
return payload.ID, nil
|
||||
}
|
||||
|
||||
func UserSessionToModel(userSession *UserSessionView) *model.UserSessionView {
|
||||
@ -66,18 +82,18 @@ func UserSessionToModel(userSession *UserSessionView) *model.UserSessionView {
|
||||
State: domain.UserSessionState(userSession.State),
|
||||
UserAgentID: userSession.UserAgentID,
|
||||
UserID: userSession.UserID,
|
||||
UserName: userSession.UserName,
|
||||
LoginName: userSession.LoginName,
|
||||
DisplayName: userSession.DisplayName,
|
||||
AvatarKey: userSession.AvatarKey,
|
||||
SelectedIDPConfigID: userSession.SelectedIDPConfigID,
|
||||
PasswordVerification: userSession.PasswordVerification,
|
||||
PasswordlessVerification: userSession.PasswordlessVerification,
|
||||
ExternalLoginVerification: userSession.ExternalLoginVerification,
|
||||
SecondFactorVerification: userSession.SecondFactorVerification,
|
||||
SecondFactorVerificationType: domain.MFAType(userSession.SecondFactorVerificationType),
|
||||
MultiFactorVerification: userSession.MultiFactorVerification,
|
||||
MultiFactorVerificationType: domain.MFAType(userSession.MultiFactorVerificationType),
|
||||
UserName: userSession.UserName.String,
|
||||
LoginName: userSession.LoginName.String,
|
||||
DisplayName: userSession.DisplayName.String,
|
||||
AvatarKey: userSession.AvatarKey.String,
|
||||
SelectedIDPConfigID: userSession.SelectedIDPConfigID.String,
|
||||
PasswordVerification: userSession.PasswordVerification.Time,
|
||||
PasswordlessVerification: userSession.PasswordlessVerification.Time,
|
||||
ExternalLoginVerification: userSession.ExternalLoginVerification.Time,
|
||||
SecondFactorVerification: userSession.SecondFactorVerification.Time,
|
||||
SecondFactorVerificationType: domain.MFAType(userSession.SecondFactorVerificationType.Int32),
|
||||
MultiFactorVerification: userSession.MultiFactorVerification.Time,
|
||||
MultiFactorVerificationType: domain.MFAType(userSession.MultiFactorVerificationType.Int32),
|
||||
Sequence: userSession.Sequence,
|
||||
}
|
||||
}
|
||||
@ -91,12 +107,13 @@ func UserSessionsToModel(userSessions []*UserSessionView) []*model.UserSessionVi
|
||||
}
|
||||
|
||||
func (v *UserSessionView) AppendEvent(event eventstore.Event) error {
|
||||
// in case anything needs to be change here check if the Reduce function needs the change as well
|
||||
v.Sequence = event.Sequence()
|
||||
v.ChangeDate = event.CreatedAt()
|
||||
switch event.Type() {
|
||||
case user.UserV1PasswordCheckSucceededType,
|
||||
user.HumanPasswordCheckSucceededType:
|
||||
v.PasswordVerification = event.CreatedAt()
|
||||
v.PasswordVerification = sql.NullTime{Time: event.CreatedAt(), Valid: true}
|
||||
v.State = int32(domain.UserSessionStateActive)
|
||||
case user.UserIDPLoginCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
@ -104,21 +121,21 @@ func (v *UserSessionView) AppendEvent(event eventstore.Event) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.ExternalLoginVerification = event.CreatedAt()
|
||||
v.SelectedIDPConfigID = data.SelectedIDPConfigID
|
||||
v.ExternalLoginVerification = sql.NullTime{Time: event.CreatedAt(), Valid: true}
|
||||
v.SelectedIDPConfigID = sql.NullString{String: data.SelectedIDPConfigID, Valid: true}
|
||||
v.State = int32(domain.UserSessionStateActive)
|
||||
case user.HumanPasswordlessTokenCheckSucceededType:
|
||||
v.PasswordlessVerification = event.CreatedAt()
|
||||
v.MultiFactorVerification = event.CreatedAt()
|
||||
v.MultiFactorVerificationType = int32(domain.MFATypeU2FUserVerification)
|
||||
v.PasswordlessVerification = sql.NullTime{Time: event.CreatedAt(), Valid: true}
|
||||
v.MultiFactorVerification = sql.NullTime{Time: event.CreatedAt(), Valid: true}
|
||||
v.MultiFactorVerificationType = sql.NullInt32{Int32: int32(domain.MFATypeU2FUserVerification)}
|
||||
v.State = int32(domain.UserSessionStateActive)
|
||||
case user.HumanPasswordlessTokenCheckFailedType,
|
||||
user.HumanPasswordlessTokenRemovedType:
|
||||
v.PasswordlessVerification = time.Time{}
|
||||
v.MultiFactorVerification = time.Time{}
|
||||
v.PasswordlessVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.MultiFactorVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
case user.UserV1PasswordCheckFailedType,
|
||||
user.HumanPasswordCheckFailedType:
|
||||
v.PasswordVerification = time.Time{}
|
||||
v.PasswordVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
case user.UserV1PasswordChangedType,
|
||||
user.HumanPasswordChangedType:
|
||||
data := new(es_model.PasswordChange)
|
||||
@ -127,7 +144,7 @@ func (v *UserSessionView) AppendEvent(event eventstore.Event) error {
|
||||
return err
|
||||
}
|
||||
if v.UserAgentID != data.UserAgentID {
|
||||
v.PasswordVerification = time.Time{}
|
||||
v.PasswordVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
}
|
||||
case user.HumanMFAOTPVerifiedType:
|
||||
data := new(es_model.OTPVerified)
|
||||
@ -167,7 +184,7 @@ func (v *UserSessionView) AppendEvent(event eventstore.Event) error {
|
||||
user.HumanU2FTokenRemovedType,
|
||||
user.HumanOTPSMSCheckFailedType,
|
||||
user.HumanOTPEmailCheckFailedType:
|
||||
v.SecondFactorVerification = time.Time{}
|
||||
v.SecondFactorVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
case user.HumanU2FTokenVerifiedType:
|
||||
data := new(es_model.WebAuthNVerify)
|
||||
err := data.SetData(event)
|
||||
@ -183,24 +200,24 @@ func (v *UserSessionView) AppendEvent(event eventstore.Event) error {
|
||||
user.HumanSignedOutType,
|
||||
user.UserLockedType,
|
||||
user.UserDeactivatedType:
|
||||
v.PasswordlessVerification = time.Time{}
|
||||
v.PasswordVerification = time.Time{}
|
||||
v.SecondFactorVerification = time.Time{}
|
||||
v.SecondFactorVerificationType = int32(domain.MFALevelNotSetUp)
|
||||
v.MultiFactorVerification = time.Time{}
|
||||
v.MultiFactorVerificationType = int32(domain.MFALevelNotSetUp)
|
||||
v.ExternalLoginVerification = time.Time{}
|
||||
v.PasswordlessVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.PasswordVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.SecondFactorVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.SecondFactorVerificationType = sql.NullInt32{Int32: int32(domain.MFALevelNotSetUp)}
|
||||
v.MultiFactorVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.MultiFactorVerificationType = sql.NullInt32{Int32: int32(domain.MFALevelNotSetUp)}
|
||||
v.ExternalLoginVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.State = int32(domain.UserSessionStateTerminated)
|
||||
case user.UserIDPLinkRemovedType, user.UserIDPLinkCascadeRemovedType:
|
||||
v.ExternalLoginVerification = time.Time{}
|
||||
v.SelectedIDPConfigID = ""
|
||||
v.ExternalLoginVerification = sql.NullTime{Time: time.Time{}, Valid: true}
|
||||
v.SelectedIDPConfigID = sql.NullString{String: "", Valid: true}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *UserSessionView) setSecondFactorVerification(verificationTime time.Time, mfaType domain.MFAType) {
|
||||
v.SecondFactorVerification = verificationTime
|
||||
v.SecondFactorVerificationType = int32(mfaType)
|
||||
v.SecondFactorVerification = sql.NullTime{Time: verificationTime, Valid: true}
|
||||
v.SecondFactorVerificationType = sql.NullInt32{Int32: int32(mfaType)}
|
||||
v.State = int32(domain.UserSessionStateActive)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
@ -33,7 +34,7 @@ func TestAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1PasswordCheckSucceededType},
|
||||
userView: &UserSessionView{},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: now()},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human password check succeeded event",
|
||||
@ -41,23 +42,23 @@ func TestAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanPasswordCheckSucceededType},
|
||||
userView: &UserSessionView{},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: now()},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user password check failed event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1PasswordCheckFailedType},
|
||||
userView: &UserSessionView{PasswordVerification: now()},
|
||||
userView: &UserSessionView{PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human password check failed event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanPasswordCheckFailedType},
|
||||
userView: &UserSessionView{PasswordVerification: now()},
|
||||
userView: &UserSessionView{PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user password changed event",
|
||||
@ -72,9 +73,9 @@ func TestAppendEvent(t *testing.T) {
|
||||
return d
|
||||
}(),
|
||||
},
|
||||
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: now()},
|
||||
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: time.Time{}},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human password changed event",
|
||||
@ -91,9 +92,9 @@ func TestAppendEvent(t *testing.T) {
|
||||
return d
|
||||
}(),
|
||||
},
|
||||
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: now()},
|
||||
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: time.Time{}},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human password changed event same user agent",
|
||||
@ -111,9 +112,9 @@ func TestAppendEvent(t *testing.T) {
|
||||
return d
|
||||
}(),
|
||||
},
|
||||
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: now()},
|
||||
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: now()},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user otp verified event",
|
||||
@ -142,7 +143,7 @@ func TestAppendEvent(t *testing.T) {
|
||||
},
|
||||
userView: &UserSessionView{UserAgentID: "id"},
|
||||
},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), SecondFactorVerification: now()},
|
||||
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user otp check succeeded event",
|
||||
@ -150,7 +151,7 @@ func TestAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1MFAOTPCheckSucceededType},
|
||||
userView: &UserSessionView{},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: now()},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human otp check succeeded event",
|
||||
@ -158,55 +159,77 @@ func TestAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanMFAOTPCheckSucceededType},
|
||||
userView: &UserSessionView{},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: now()},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user otp check failed event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1MFAOTPCheckFailedType},
|
||||
userView: &UserSessionView{SecondFactorVerification: now()},
|
||||
userView: &UserSessionView{SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human otp check failed event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanMFAOTPCheckFailedType},
|
||||
userView: &UserSessionView{SecondFactorVerification: now()},
|
||||
userView: &UserSessionView{SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user otp removed event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1MFAOTPRemovedType},
|
||||
userView: &UserSessionView{SecondFactorVerification: now()},
|
||||
userView: &UserSessionView{SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append human otp removed event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanMFAOTPRemovedType},
|
||||
userView: &UserSessionView{SecondFactorVerification: now()},
|
||||
userView: &UserSessionView{SecondFactorVerification: sql.NullTime{Time: now(), Valid: true}},
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
|
||||
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true}},
|
||||
},
|
||||
{
|
||||
name: "append user signed out event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1SignedOutType},
|
||||
userView: &UserSessionView{PasswordVerification: now(), SecondFactorVerification: now()},
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.UserV1SignedOutType},
|
||||
userView: &UserSessionView{
|
||||
PasswordVerification: sql.NullTime{Time: now(), Valid: true},
|
||||
SecondFactorVerification: sql.NullTime{Time: now(), Valid: true},
|
||||
},
|
||||
},
|
||||
result: &UserSessionView{
|
||||
ChangeDate: now(),
|
||||
PasswordVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
SecondFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
ExternalLoginVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
PasswordlessVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
MultiFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
State: 1,
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, SecondFactorVerification: time.Time{}, State: 1},
|
||||
},
|
||||
{
|
||||
name: "append human signed out event",
|
||||
args: args{
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanSignedOutType},
|
||||
userView: &UserSessionView{PasswordVerification: now(), SecondFactorVerification: now()},
|
||||
event: &es_models.Event{CreationDate: now(), Typ: user.HumanSignedOutType},
|
||||
userView: &UserSessionView{
|
||||
PasswordVerification: sql.NullTime{Time: now(), Valid: true},
|
||||
SecondFactorVerification: sql.NullTime{Time: now(), Valid: true},
|
||||
},
|
||||
},
|
||||
result: &UserSessionView{
|
||||
ChangeDate: now(),
|
||||
PasswordVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
SecondFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
ExternalLoginVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
PasswordlessVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
MultiFactorVerification: sql.NullTime{Time: time.Time{}, Valid: true},
|
||||
State: 1,
|
||||
},
|
||||
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, SecondFactorVerification: time.Time{}, State: 1},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -42,74 +42,9 @@ func RefreshTokensByUserID(db *gorm.DB, table, userID, instanceID string) ([]*us
|
||||
return tokens, err
|
||||
}
|
||||
|
||||
func PutRefreshToken(db *gorm.DB, table string, token *usr_model.RefreshTokenView) error {
|
||||
save := repository.PrepareSaveOnConflict(table,
|
||||
[]string{"client_id", "user_agent_id", "user_id"},
|
||||
[]string{"id", "creation_date", "change_date", "token", "auth_time", "idle_expiration", "expiration", "sequence", "scopes", "audience", "amr"},
|
||||
)
|
||||
return save(db, token)
|
||||
}
|
||||
|
||||
func PutRefreshTokens(db *gorm.DB, table string, tokens ...*usr_model.RefreshTokenView) error {
|
||||
save := repository.PrepareBulkSave(table)
|
||||
t := make([]interface{}, len(tokens))
|
||||
for i, token := range tokens {
|
||||
t[i] = token
|
||||
}
|
||||
return save(db, t...)
|
||||
}
|
||||
|
||||
func SearchRefreshTokens(db *gorm.DB, table string, req *model.RefreshTokenSearchRequest) ([]*usr_model.RefreshTokenView, uint64, error) {
|
||||
tokens := make([]*usr_model.RefreshTokenView, 0)
|
||||
query := repository.PrepareSearchQuery(table, usr_model.RefreshTokenSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
count, err := query(db, &tokens)
|
||||
return tokens, count, err
|
||||
}
|
||||
|
||||
func DeleteRefreshToken(db *gorm.DB, table, tokenID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyRefreshTokenID), tokenID},
|
||||
repository.Key{usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteSessionRefreshTokens(db *gorm.DB, table, agentID, userID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyUserAgentID), Value: agentID},
|
||||
repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyUserID), Value: userID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteUserRefreshTokens(db *gorm.DB, table, userID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyUserID), userID},
|
||||
repository.Key{usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteApplicationRefreshTokens(db *gorm.DB, table string, instanceID string, appIDs []string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), Value: instanceID},
|
||||
repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyApplicationID), Value: appIDs},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteOrgRefreshTokens(db *gorm.DB, table string, instanceID, orgID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), Value: instanceID},
|
||||
repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyResourceOwner), Value: orgID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteInstanceRefreshTokens(db *gorm.DB, table string, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKey(table,
|
||||
usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID),
|
||||
instanceID,
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
@ -47,74 +47,3 @@ func TokensByUserID(db *gorm.DB, table, userID, instanceID string) ([]*usr_model
|
||||
_, err := query(db, &tokens)
|
||||
return tokens, err
|
||||
}
|
||||
|
||||
func PutToken(db *gorm.DB, table string, token *usr_model.TokenView) error {
|
||||
save := repository.PrepareSave(table)
|
||||
return save(db, token)
|
||||
}
|
||||
|
||||
func PutTokens(db *gorm.DB, table string, tokens ...*usr_model.TokenView) error {
|
||||
save := repository.PrepareBulkSave(table)
|
||||
t := make([]interface{}, len(tokens))
|
||||
for i, token := range tokens {
|
||||
t[i] = token
|
||||
}
|
||||
return save(db, t...)
|
||||
}
|
||||
|
||||
func DeleteToken(db *gorm.DB, table, tokenID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyTokenID), Value: tokenID},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteSessionTokens(db *gorm.DB, table, agentID, userID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyUserAgentID), Value: agentID},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyUserID), Value: userID},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteUserTokens(db *gorm.DB, table, userID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyUserID), Value: userID},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteTokensFromRefreshToken(db *gorm.DB, table, refreshTokenID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyRefreshTokenID), Value: refreshTokenID},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteApplicationTokens(db *gorm.DB, table, instanceID string, appIDs []string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyApplicationID), Value: appIDs},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteInstanceTokens(db *gorm.DB, table, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKey(table,
|
||||
usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID),
|
||||
instanceID,
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteOrgTokens(db *gorm.DB, table, instanceID, orgID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyResourceOwner), Value: orgID},
|
||||
repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
93
internal/user/repository/view/user_by_id.sql
Normal file
93
internal/user/repository/view/user_by_id.sql
Normal file
@ -0,0 +1,93 @@
|
||||
WITH auth_methods AS (
|
||||
SELECT
|
||||
user_id
|
||||
, method_type
|
||||
, token_id
|
||||
, state
|
||||
, instance_id
|
||||
, name
|
||||
FROM
|
||||
projections.user_auth_methods4
|
||||
WHERE
|
||||
instance_id = $1
|
||||
AND user_id = $2
|
||||
),
|
||||
verified_auth_methods AS (
|
||||
SELECT
|
||||
method_type
|
||||
FROM
|
||||
auth_methods
|
||||
WHERE state = 2
|
||||
)
|
||||
SELECT
|
||||
u.id
|
||||
, u.creation_date
|
||||
, LEAST(u.change_date, au.change_date) AS change_date
|
||||
, u.resource_owner
|
||||
, u.state AS user_state
|
||||
, au.password_set
|
||||
, h.password_change_required
|
||||
, au.password_change
|
||||
, au.last_login
|
||||
, u.username AS user_name
|
||||
, (SELECT array_agg(ll.login_name) login_names FROM projections.login_names3 ll
|
||||
WHERE u.instance_id = ll.instance_id AND u.id = ll.user_id
|
||||
GROUP BY ll.user_id, ll.instance_id) AS login_names
|
||||
, l.login_name
|
||||
, h.first_name
|
||||
, h.last_name
|
||||
, h.nick_name
|
||||
, h.display_name
|
||||
, h.preferred_language
|
||||
, h.gender
|
||||
, h.email
|
||||
, h.is_email_verified
|
||||
, h.phone
|
||||
, h.is_phone_verified
|
||||
, (SELECT COALESCE((SELECT state FROM auth_methods WHERE method_type = 1), 0)) AS otp_state
|
||||
, CASE
|
||||
WHEN EXISTS (SELECT true FROM verified_auth_methods WHERE method_type = 3) THEN 2
|
||||
WHEN EXISTS (SELECT true FROM verified_auth_methods WHERE method_type = 2) THEN 1
|
||||
ELSE 0
|
||||
END AS mfa_max_set_up
|
||||
, au.mfa_init_skipped
|
||||
, u.sequence
|
||||
, au.init_required
|
||||
, au.username_change_required
|
||||
, m.name AS machine_name
|
||||
, m.description AS machine_description
|
||||
, u.type AS user_type
|
||||
, (SELECT
|
||||
JSONB_AGG(json_build_object('webAuthNTokenId', token_id, 'webAuthNTokenName', name, 'state', state))
|
||||
FROM auth_methods
|
||||
WHERE method_type = 2
|
||||
) AS u2f_tokens
|
||||
, (SELECT
|
||||
JSONB_AGG(json_build_object('webAuthNTokenId', token_id, 'webAuthNTokenName', name, 'state', state))
|
||||
FROM auth_methods
|
||||
WHERE method_type = 3
|
||||
) AS passwordless_tokens
|
||||
, h.avatar_key
|
||||
, au.passwordless_init_required
|
||||
, au.password_init_required
|
||||
, u.instance_id
|
||||
, (SELECT EXISTS (SELECT true FROM verified_auth_methods WHERE method_type = 6)) AS otp_sms_added
|
||||
, (SELECT EXISTS (SELECT true FROM verified_auth_methods WHERE method_type = 7)) AS otp_email_added
|
||||
FROM projections.users12 u
|
||||
LEFT JOIN projections.users12_humans h
|
||||
ON u.instance_id = h.instance_id
|
||||
AND u.id = h.user_id
|
||||
LEFT JOIN projections.login_names3 l
|
||||
ON u.instance_id = l.instance_id
|
||||
AND u.id = l.user_id
|
||||
AND l.is_primary = true
|
||||
LEFT JOIN projections.users12_machines m
|
||||
ON u.instance_id = m.instance_id
|
||||
AND u.id = m.user_id
|
||||
LEFT JOIN auth.users3 au
|
||||
ON u.instance_id = au.instance_id
|
||||
AND u.id = au.id
|
||||
WHERE
|
||||
u.instance_id = $1
|
||||
AND u.id = $2
|
||||
LIMIT 1;
|
@ -5,12 +5,8 @@ import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
usr_model "github.com/zitadel/zitadel/internal/user/model"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/view/repository"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
@ -46,38 +42,8 @@ func UserSessionsByAgentID(db *database.DB, agentID, instanceID string) (userSes
|
||||
return userSessions, err
|
||||
}
|
||||
|
||||
func PutUserSession(db *gorm.DB, table string, session *model.UserSessionView) error {
|
||||
save := repository.PrepareSave(table)
|
||||
return save(db, session)
|
||||
}
|
||||
|
||||
func DeleteUserSessions(db *gorm.DB, table, userID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyUserID), Value: userID},
|
||||
repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteInstanceUserSessions(db *gorm.DB, table, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKey(table,
|
||||
model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID),
|
||||
instanceID,
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteOrgUserSessions(db *gorm.DB, table, instanceID, orgID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyResourceOwner), Value: orgID},
|
||||
repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), Value: instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func scanUserSession(row *sql.Row) (*model.UserSessionView, error) {
|
||||
session := new(model.UserSessionView)
|
||||
var userName, loginName, displayName, avatarKey sql.NullString
|
||||
err := row.Scan(
|
||||
&session.CreationDate,
|
||||
&session.ChangeDate,
|
||||
@ -85,10 +51,10 @@ func scanUserSession(row *sql.Row) (*model.UserSessionView, error) {
|
||||
&session.State,
|
||||
&session.UserAgentID,
|
||||
&session.UserID,
|
||||
&userName,
|
||||
&loginName,
|
||||
&displayName,
|
||||
&avatarKey,
|
||||
&session.UserName,
|
||||
&session.LoginName,
|
||||
&session.DisplayName,
|
||||
&session.AvatarKey,
|
||||
&session.SelectedIDPConfigID,
|
||||
&session.PasswordVerification,
|
||||
&session.PasswordlessVerification,
|
||||
@ -103,10 +69,6 @@ func scanUserSession(row *sql.Row) (*model.UserSessionView, error) {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, zerrors.ThrowNotFound(nil, "VIEW-NGBs1", "Errors.UserSession.NotFound")
|
||||
}
|
||||
session.UserName = userName.String
|
||||
session.LoginName = loginName.String
|
||||
session.DisplayName = displayName.String
|
||||
session.AvatarKey = avatarKey.String
|
||||
return session, err
|
||||
}
|
||||
|
||||
@ -114,7 +76,6 @@ func scanUserSessions(rows *sql.Rows) ([]*model.UserSessionView, error) {
|
||||
sessions := make([]*model.UserSessionView, 0)
|
||||
for rows.Next() {
|
||||
session := new(model.UserSessionView)
|
||||
var userName, loginName, displayName, avatarKey sql.NullString
|
||||
err := rows.Scan(
|
||||
&session.CreationDate,
|
||||
&session.ChangeDate,
|
||||
@ -122,10 +83,10 @@ func scanUserSessions(rows *sql.Rows) ([]*model.UserSessionView, error) {
|
||||
&session.State,
|
||||
&session.UserAgentID,
|
||||
&session.UserID,
|
||||
&userName,
|
||||
&loginName,
|
||||
&displayName,
|
||||
&avatarKey,
|
||||
&session.UserName,
|
||||
&session.LoginName,
|
||||
&session.DisplayName,
|
||||
&session.AvatarKey,
|
||||
&session.SelectedIDPConfigID,
|
||||
&session.PasswordVerification,
|
||||
&session.PasswordlessVerification,
|
||||
@ -140,10 +101,6 @@ func scanUserSessions(rows *sql.Rows) ([]*model.UserSessionView, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
session.UserName = userName.String
|
||||
session.LoginName = loginName.String
|
||||
session.DisplayName = displayName.String
|
||||
session.AvatarKey = avatarKey.String
|
||||
sessions = append(sessions, session)
|
||||
}
|
||||
|
||||
|
@ -1,98 +1,42 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"context"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"errors"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
usr_model "github.com/zitadel/zitadel/internal/user/model"
|
||||
"github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/view/repository"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
//go:embed user_by_id.sql
|
||||
var userByIDQuery string
|
||||
|
||||
func UserByID(db *gorm.DB, table, userID, instanceID string) (*model.UserView, error) {
|
||||
user := new(model.UserView)
|
||||
userIDQuery := &model.UserSearchQuery{
|
||||
Key: usr_model.UserSearchKeyUserID,
|
||||
Method: domain.SearchMethodEquals,
|
||||
Value: userID,
|
||||
}
|
||||
instanceIDQuery := &model.UserSearchQuery{
|
||||
Key: usr_model.UserSearchKeyInstanceID,
|
||||
Method: domain.SearchMethodEquals,
|
||||
Value: instanceID,
|
||||
}
|
||||
ownerRemovedQuery := &model.UserSearchQuery{
|
||||
Key: usr_model.UserSearchOwnerRemoved,
|
||||
Method: domain.SearchMethodEquals,
|
||||
Value: false,
|
||||
}
|
||||
query := repository.PrepareGetByQuery(table, userIDQuery, instanceIDQuery, ownerRemovedQuery)
|
||||
err := query(db, user)
|
||||
if zerrors.IsNotFound(err) {
|
||||
return nil, zerrors.ThrowNotFound(nil, "VIEW-sj8Sw", "Errors.User.NotFound")
|
||||
}
|
||||
user.SetEmptyUserType()
|
||||
return user, err
|
||||
}
|
||||
|
||||
func UsersByOrgID(db *gorm.DB, table, orgID, instanceID string) ([]*model.UserView, error) {
|
||||
users := make([]*model.UserView, 0)
|
||||
orgIDQuery := &usr_model.UserSearchQuery{
|
||||
Key: usr_model.UserSearchKeyResourceOwner,
|
||||
Method: domain.SearchMethodEquals,
|
||||
Value: orgID,
|
||||
query := db.Raw(userByIDQuery, instanceID, userID)
|
||||
|
||||
tx := query.BeginTx(context.Background(), &sql.TxOptions{ReadOnly: true})
|
||||
defer func() {
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
logging.OnError(err).Info("commit failed")
|
||||
}
|
||||
tx.RollbackUnlessCommitted()
|
||||
}()
|
||||
|
||||
err := tx.Scan(user).Error
|
||||
if err == nil {
|
||||
user.SetEmptyUserType()
|
||||
return user, nil
|
||||
}
|
||||
instanceIDQuery := &usr_model.UserSearchQuery{
|
||||
Key: usr_model.UserSearchKeyInstanceID,
|
||||
Method: domain.SearchMethodEquals,
|
||||
Value: instanceID,
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, zerrors.ThrowNotFound(err, "VIEW-hodc6", "object not found")
|
||||
}
|
||||
ownerRemovedQuery := &usr_model.UserSearchQuery{
|
||||
Key: usr_model.UserSearchOwnerRemoved,
|
||||
Method: domain.SearchMethodEquals,
|
||||
Value: false,
|
||||
}
|
||||
query := repository.PrepareSearchQuery(table, model.UserSearchRequest{
|
||||
Queries: []*usr_model.UserSearchQuery{orgIDQuery, instanceIDQuery, ownerRemovedQuery},
|
||||
})
|
||||
_, err := query(db, &users)
|
||||
return users, err
|
||||
}
|
||||
|
||||
func PutUsers(db *gorm.DB, table string, users ...*model.UserView) error {
|
||||
save := repository.PrepareBulkSave(table)
|
||||
u := make([]interface{}, len(users))
|
||||
for i, user := range users {
|
||||
u[i] = user
|
||||
}
|
||||
return save(db, u...)
|
||||
}
|
||||
|
||||
func PutUser(db *gorm.DB, table string, user *model.UserView) error {
|
||||
save := repository.PrepareSave(table)
|
||||
return save(db, user)
|
||||
}
|
||||
|
||||
func DeleteUser(db *gorm.DB, table, userID, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKeys(table,
|
||||
repository.Key{model.UserSearchKey(usr_model.UserSearchKeyUserID), userID},
|
||||
repository.Key{model.UserSearchKey(usr_model.UserSearchKeyInstanceID), instanceID},
|
||||
)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteInstanceUsers(db *gorm.DB, table, instanceID string) error {
|
||||
delete := repository.PrepareDeleteByKey(table, model.UserSearchKey(usr_model.UserSearchKeyInstanceID), instanceID)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func UpdateOrgOwnerRemovedUsers(db *gorm.DB, table, instanceID, aggID string) error {
|
||||
update := repository.PrepareUpdateByKeys(table,
|
||||
model.UserSearchKey(usr_model.UserSearchOwnerRemoved),
|
||||
true,
|
||||
repository.Key{Key: model.UserSearchKey(usr_model.UserSearchKeyInstanceID), Value: instanceID},
|
||||
repository.Key{Key: model.UserSearchKey(usr_model.UserSearchKeyResourceOwner), Value: aggID},
|
||||
)
|
||||
return update(db)
|
||||
logging.WithFields("table ", table).WithError(err).Warn("get from cache error")
|
||||
return nil, zerrors.ThrowInternal(err, "VIEW-qJBg9", "cache error")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user