From 9271623ec9c819984e418b1315499fc9774465a0 Mon Sep 17 00:00:00 2001 From: Silvan Date: Thu, 7 Jul 2022 14:58:00 +0200 Subject: [PATCH] fix: load auth users (#3907) * fix: load auth users * fix: add triggerbulk * fix: build pre-release * fix even more french translations * fix: build version Co-authored-by: Livio Spring --- .releaserc.js | 2 +- internal/api/grpc/management/user.go | 2 +- .../middleware/translation_interceptor.go | 7 +- .../api/grpc/server/middleware/translator.go | 11 ++- .../api/ui/login/init_password_handler.go | 2 +- .../api/ui/login/password_reset_handler.go | 2 +- internal/api/ui/login/static/i18n/fr.yaml | 16 ++--- .../repository/eventsourcing/repository.go | 2 +- .../repository/eventsourcing/view/user.go | 72 ++++++++++++++++++- .../repository/eventsourcing/view/view.go | 5 +- internal/query/user.go | 10 ++- internal/static/i18n/fr.yaml | 4 +- 12 files changed, 105 insertions(+), 30 deletions(-) diff --git a/.releaserc.js b/.releaserc.js index 5c4725f1cc..a7df798669 100644 --- a/.releaserc.js +++ b/.releaserc.js @@ -3,7 +3,7 @@ module.exports = { {name: 'main'}, {name: '1.x.x', range: '1.x.x', channel: '1.x.x'}, {name: 'v2-alpha', prerelease: true}, - {name: 'notify-users', prerelease: true}, + {name: 'auth-users', prerelease: true}, ], plugins: [ "@semantic-release/commit-analyzer" diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index 5fd3bc7822..7aa0e1a3e0 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -44,7 +44,7 @@ func (s *Server) GetUserByLoginNameGlobal(ctx context.Context, req *mgmt_pb.GetU if err != nil { return nil, err } - user, err := s.query.GetUser(ctx, loginName) + user, err := s.query.GetUser(ctx, true, loginName) if err != nil { return nil, err } diff --git a/internal/api/grpc/server/middleware/translation_interceptor.go b/internal/api/grpc/server/middleware/translation_interceptor.go index 6380c3e382..7761e94b2c 100644 --- a/internal/api/grpc/server/middleware/translation_interceptor.go +++ b/internal/api/grpc/server/middleware/translation_interceptor.go @@ -3,6 +3,7 @@ package middleware import ( "context" + "github.com/zitadel/logging" "google.golang.org/grpc" "github.com/zitadel/zitadel/internal/api/authz" @@ -13,7 +14,11 @@ import ( func TranslationHandler() func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { resp, err := handler(ctx, req) - translator := newZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage()) + translator, translatorError := newZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage()) + if translatorError != nil { + logging.New().WithError(translatorError).Error("could not load translator") + return resp, err + } if loc, ok := resp.(localizers); ok && resp != nil { translateFields(ctx, loc, translator) } diff --git a/internal/api/grpc/server/middleware/translator.go b/internal/api/grpc/server/middleware/translator.go index 6d5b1dd669..f42741db0b 100644 --- a/internal/api/grpc/server/middleware/translator.go +++ b/internal/api/grpc/server/middleware/translator.go @@ -40,16 +40,13 @@ func translateError(ctx context.Context, err error, translator *i18n.Translator) return err } -func newZitadelTranslator(defaultLanguage language.Tag) *i18n.Translator { +func newZitadelTranslator(defaultLanguage language.Tag) (*i18n.Translator, error) { return translatorFromNamespace("zitadel", defaultLanguage) } -func translatorFromNamespace(namespace string, defaultLanguage language.Tag) *i18n.Translator { +func translatorFromNamespace(namespace string, defaultLanguage language.Tag) (*i18n.Translator, error) { dir, err := fs.NewWithNamespace(namespace) - logging.LogWithFields("ERROR-7usEW", "namespace", namespace).OnError(err).Panic("unable to get namespace") + logging.WithFields("namespace", namespace).OnError(err).Panic("unable to get namespace") - translator, err := i18n.NewTranslator(dir, defaultLanguage, "") - logging.Log("ERROR-Sk8sf").OnError(err).Panic("unable to get i18n translator") - - return translator + return i18n.NewTranslator(dir, defaultLanguage, "") } diff --git a/internal/api/ui/login/init_password_handler.go b/internal/api/ui/login/init_password_handler.go index b2fc4ee6c8..0b88afd224 100644 --- a/internal/api/ui/login/init_password_handler.go +++ b/internal/api/ui/login/init_password_handler.go @@ -107,7 +107,7 @@ func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authRe l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) return } - user, err := l.query.GetUser(setContext(r.Context(), userOrg), loginName) + user, err := l.query.GetUser(setContext(r.Context(), userOrg), false, loginName) if err != nil { l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) return diff --git a/internal/api/ui/login/password_reset_handler.go b/internal/api/ui/login/password_reset_handler.go index d022db316c..ef567732a9 100644 --- a/internal/api/ui/login/password_reset_handler.go +++ b/internal/api/ui/login/password_reset_handler.go @@ -23,7 +23,7 @@ func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) { l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) return } - user, err := l.query.GetUser(setContext(r.Context(), authReq.UserOrgID), loginName) + user, err := l.query.GetUser(setContext(r.Context(), authReq.UserOrgID), false, loginName) if err != nil { l.renderPasswordResetDone(w, r, authReq, err) return diff --git a/internal/api/ui/login/static/i18n/fr.yaml b/internal/api/ui/login/static/i18n/fr.yaml index a1671a8086..10022d80e0 100644 --- a/internal/api/ui/login/static/i18n/fr.yaml +++ b/internal/api/ui/login/static/i18n/fr.yaml @@ -12,14 +12,14 @@ Login: NextButtonText: suivant SelectAccount: - Title: Select account - Description: Use your ZITADEL-Account - TitleLinking: Select account for user linking - DescriptionLinking: Select your account to link with your external user. - OtherUser: Other User - SessionState0: active - SessionState1: inactive - MustBeMemberOfOrg: The user must be member of the {{.OrgName}} organisation. + Title: Sélectionner un compte + Description: Utilisez votre compte ZITADEL + TitleLinking: Sélectionnez le compte pour le lien avec l'utilisateur + DescriptionLinking: Sélectionnez votre compte pour établir un lien avec votre utilisateur externe. + OtherUser: Autre utilisateur + SessionState0: actif + SessionState1: inactif + MustBeMemberOfOrg: L'utilisateur doit être membre de l'organisation {{.OrgName}}. Password: Title: Mot de passe diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index bd6d0c796e..b21acba79d 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -40,7 +40,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, command *command.Comma } idGenerator := id.SonyFlakeGenerator() - view, err := auth_view.StartView(dbClient, oidcEncryption, queries, idGenerator) + view, err := auth_view.StartView(dbClient, oidcEncryption, queries, idGenerator, es) if err != nil { return nil, err } diff --git a/internal/auth/repository/eventsourcing/view/user.go b/internal/auth/repository/eventsourcing/view/user.go index 3c232aba37..bbc5d3e1e5 100644 --- a/internal/auth/repository/eventsourcing/view/user.go +++ b/internal/auth/repository/eventsourcing/view/user.go @@ -1,8 +1,12 @@ package view import ( + "context" + + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore/v1/models" + "github.com/zitadel/zitadel/internal/query" usr_model "github.com/zitadel/zitadel/internal/user/model" "github.com/zitadel/zitadel/internal/user/repository/view" "github.com/zitadel/zitadel/internal/user/repository/view/model" @@ -18,15 +22,77 @@ func (v *View) UserByID(userID, instanceID string) (*model.UserView, error) { } func (v *View) UserByUsername(userName, instanceID string) (*model.UserView, error) { - return view.UserByUserName(v.Db, userTable, userName, instanceID) + query, err := query.NewUserUsernameSearchQuery(userName, query.TextEquals) + if err != nil { + return nil, err + } + + return v.userByID(instanceID, query) } func (v *View) UserByLoginName(loginName, instanceID string) (*model.UserView, error) { - return view.UserByLoginName(v.Db, userTable, loginName, instanceID) + loginNameQuery, err := query.NewUserLoginNamesSearchQuery(loginName) + if err != nil { + return nil, err + } + + return v.userByID(instanceID, loginNameQuery) } func (v *View) UserByLoginNameAndResourceOwner(loginName, resourceOwner, instanceID string) (*model.UserView, error) { - return view.UserByLoginNameAndResourceOwner(v.Db, userTable, loginName, resourceOwner, instanceID) + loginNameQuery, err := query.NewUserLoginNamesSearchQuery(loginName) + if err != nil { + return nil, err + } + resourceOwnerQuery, err := query.NewUserResourceOwnerSearchQuery(resourceOwner, query.TextEquals) + if err != nil { + return nil, err + } + + return v.userByID(instanceID, loginNameQuery, resourceOwnerQuery) +} + +func (v *View) userByID(instanceID string, queries ...query.SearchQuery) (*model.UserView, error) { + ctx := authz.WithInstanceID(context.Background(), instanceID) + + queriedUser, err := v.query.GetUser(ctx, true, queries...) + if err != nil { + return nil, err + } + + user, err := view.UserByID(v.Db, userTable, queriedUser.ID, instanceID) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + + if err != nil { + user = new(model.UserView) + } + + query, err := view.UserByIDQuery(queriedUser.ID, instanceID, user.Sequence) + if err != nil { + return nil, err + } + events, err := v.es.FilterEvents(ctx, query) + if err != nil && user.Sequence == 0 { + return nil, err + } else if err != nil { + return user, nil + } + + userCopy := *user + + for _, event := range events { + if err := user.AppendEvent(event); err != nil { + return &userCopy, nil + } + } + + if user.State == int32(usr_model.UserStateDeleted) { + return nil, errors.ThrowNotFound(nil, "VIEW-r4y8r", "Errors.User.NotFound") + } + + return user, nil } func (v *View) UsersByOrgID(orgID, instanceID string) ([]*model.UserView, error) { diff --git a/internal/auth/repository/eventsourcing/view/view.go b/internal/auth/repository/eventsourcing/view/view.go index 0bb91801e6..54c57e99f7 100644 --- a/internal/auth/repository/eventsourcing/view/view.go +++ b/internal/auth/repository/eventsourcing/view/view.go @@ -6,6 +6,7 @@ import ( "github.com/jinzhu/gorm" "github.com/zitadel/zitadel/internal/crypto" + eventstore "github.com/zitadel/zitadel/internal/eventstore/v1" "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/query" ) @@ -15,9 +16,10 @@ type View struct { keyAlgorithm crypto.EncryptionAlgorithm idGenerator id.Generator query *query.Queries + es eventstore.Eventstore } -func StartView(sqlClient *sql.DB, keyAlgorithm crypto.EncryptionAlgorithm, queries *query.Queries, idGenerator id.Generator) (*View, error) { +func StartView(sqlClient *sql.DB, keyAlgorithm crypto.EncryptionAlgorithm, queries *query.Queries, idGenerator id.Generator, es eventstore.Eventstore) (*View, error) { gorm, err := gorm.Open("postgres", sqlClient) if err != nil { return nil, err @@ -27,6 +29,7 @@ func StartView(sqlClient *sql.DB, keyAlgorithm crypto.EncryptionAlgorithm, queri keyAlgorithm: keyAlgorithm, idGenerator: idGenerator, query: queries, + es: es, }, nil } diff --git a/internal/query/user.go b/internal/query/user.go index 1d928f38fe..a4a4bea7d6 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -292,8 +292,8 @@ var ( } ) -func (q *Queries) GetUserByID(ctx context.Context, shouldTriggered bool, userID string, queries ...SearchQuery) (*User, error) { - if shouldTriggered { +func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userID string, queries ...SearchQuery) (*User, error) { + if shouldTriggerBulk { projection.UserProjection.TriggerBulk(ctx) } @@ -314,7 +314,11 @@ func (q *Queries) GetUserByID(ctx context.Context, shouldTriggered bool, userID return scan(row) } -func (q *Queries) GetUser(ctx context.Context, queries ...SearchQuery) (*User, error) { +func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, queries ...SearchQuery) (*User, error) { + if shouldTriggerBulk { + projection.UserProjection.TriggerBulk(ctx) + } + instanceID := authz.GetInstance(ctx).InstanceID() query, scan := prepareUserQuery(instanceID) for _, q := range queries { diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index 3678cfe2ab..68684e83d8 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -39,8 +39,8 @@ Errors: NotFound: Générateur de secret non trouvé SMSConfig: NotFound: Configuration SMS non trouvée - AlreadyActive: Configuration SMS déjà active - AlreadyDeactivated: Configuration SMS déjà désactivée + AlreadyActive: Configuration SMS déjà active + AlreadyDeactivated: Configuration SMS déjà désactivée SMTPConfig: NotFound: Configuration SMTP non trouvée AlreadyExists: La configuration SMTP existe déjà