fix: move activity log to queries and remove old code (#3096)

* move changes to queries and remove old code

* fix changes query

* remove unused code

* fix sorting

* fix sorting

* refactor and remove old code

* remove accidental go.mod replace

* add missing file

* remove listDetail from ChangesResponse
This commit is contained in:
Livio Amstutz 2022-01-26 10:16:33 +01:00 committed by GitHub
parent 52da2354a3
commit e99b7f4972
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 579 additions and 3565 deletions

View File

@ -23,14 +23,13 @@ import (
"github.com/caos/zitadel/internal/api/oidc" "github.com/caos/zitadel/internal/api/oidc"
auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing" auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
"github.com/caos/zitadel/internal/authz" "github.com/caos/zitadel/internal/authz"
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" authz_repo "github.com/caos/zitadel/internal/authz/repository"
"github.com/caos/zitadel/internal/command" "github.com/caos/zitadel/internal/command"
"github.com/caos/zitadel/internal/config" "github.com/caos/zitadel/internal/config"
sd "github.com/caos/zitadel/internal/config/systemdefaults" sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
mgmt_es "github.com/caos/zitadel/internal/management/repository/eventsourcing"
"github.com/caos/zitadel/internal/notification" "github.com/caos/zitadel/internal/notification"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/query/projection" "github.com/caos/zitadel/internal/query/projection"
@ -64,7 +63,6 @@ type Config struct {
AuthZ authz.Config AuthZ authz.Config
Auth auth_es.Config Auth auth_es.Config
Admin admin_es.Config Admin admin_es.Config
Mgmt mgmt_es.Config
API api.Config API api.Config
UI ui.Config UI ui.Config
@ -158,10 +156,10 @@ func startZitadel(configPaths []string) {
} }
keyChan := make(chan interface{}) keyChan := make(chan interface{})
queries, err := query.StartQueries(ctx, esQueries, conf.Projections, conf.SystemDefaults, keyChan) queries, err := query.StartQueries(ctx, esQueries, conf.Projections, conf.SystemDefaults, keyChan, conf.InternalAuthZ.RolePermissionMappings)
logging.Log("MAIN-WpeJY").OnError(err).Fatal("cannot start queries") logging.Log("MAIN-WpeJY").OnError(err).Fatal("cannot start queries")
authZRepo, err := authz.Start(ctx, conf.AuthZ, conf.InternalAuthZ, conf.SystemDefaults, queries) authZRepo, err := authz.Start(conf.AuthZ, conf.SystemDefaults, queries)
logging.Log("MAIN-s9KOw").OnError(err).Fatal("error starting authz repo") logging.Log("MAIN-s9KOw").OnError(err).Fatal("error starting authz repo")
esCommands, err := eventstore.StartWithUser(conf.EventstoreBase, conf.Commands.Eventstore) esCommands, err := eventstore.StartWithUser(conf.EventstoreBase, conf.Commands.Eventstore)
@ -177,15 +175,15 @@ func startZitadel(configPaths []string) {
var authRepo *auth_es.EsRepository var authRepo *auth_es.EsRepository
if *authEnabled || *oidcEnabled || *loginEnabled { if *authEnabled || *oidcEnabled || *loginEnabled {
authRepo, err = auth_es.Start(conf.Auth, conf.InternalAuthZ, conf.SystemDefaults, commands, queries, authZRepo, esQueries) authRepo, err = auth_es.Start(conf.Auth, conf.SystemDefaults, commands, queries)
logging.Log("MAIN-9oRw6").OnError(err).Fatal("error starting auth repo") logging.Log("MAIN-9oRw6").OnError(err).Fatal("error starting auth repo")
} }
repo := struct { repo := struct {
authz_repo.EsRepository authz_repo.Repository
query.Queries query.Queries
}{ }{
*authZRepo, authZRepo,
*queries, *queries,
} }
@ -215,33 +213,27 @@ func startUI(ctx context.Context, conf *Config, authRepo *auth_es.EsRepository,
uis.Start(ctx) uis.Start(ctx)
} }
func startAPI(ctx context.Context, conf *Config, verifier *internal_authz.TokenVerifier, authZRepo *authz_repo.EsRepository, authRepo *auth_es.EsRepository, command *command.Commands, query *query.Queries, static static.Storage, es *eventstore.Eventstore, projections types.SQL, keyChan <-chan interface{}) { func startAPI(ctx context.Context, conf *Config, verifier *internal_authz.TokenVerifier, authZRepo authz_repo.Repository, authRepo *auth_es.EsRepository, command *command.Commands, query *query.Queries, static static.Storage, es *eventstore.Eventstore, projections types.SQL, keyChan <-chan interface{}) {
roles := make([]string, len(conf.InternalAuthZ.RolePermissionMappings)) repo, err := admin_es.Start(ctx, conf.Admin, conf.SystemDefaults, command, static, *localDevMode)
for i, role := range conf.InternalAuthZ.RolePermissionMappings {
roles[i] = role.Role
}
repo, err := admin_es.Start(ctx, conf.Admin, conf.SystemDefaults, command, static, roles, *localDevMode)
logging.Log("API-D42tq").OnError(err).Fatal("error starting auth repo") logging.Log("API-D42tq").OnError(err).Fatal("error starting auth repo")
apis := api.Create(conf.API, conf.InternalAuthZ, query, authZRepo, authRepo, repo, conf.SystemDefaults) apis := api.Create(conf.API, conf.InternalAuthZ, query, authZRepo, authRepo, repo, conf.SystemDefaults)
if *adminEnabled { if *adminEnabled {
apis.RegisterServer(ctx, admin.CreateServer(command, query, repo, conf.SystemDefaults.Domain, conf.Admin.APIDomain+"/assets/v1/")) apis.RegisterServer(ctx, admin.CreateServer(command, query, repo, conf.SystemDefaults.Domain, conf.API.Domain+"/assets/v1/"))
} }
managementRepo, err := mgmt_es.Start(conf.Mgmt, conf.SystemDefaults, roles, query, static)
logging.Log("API-Gd2qq").OnError(err).Fatal("error starting management repo")
if *managementEnabled { if *managementEnabled {
apis.RegisterServer(ctx, management.CreateServer(command, query, managementRepo, conf.SystemDefaults, conf.Mgmt.APIDomain+"/assets/v1/")) apis.RegisterServer(ctx, management.CreateServer(command, query, conf.SystemDefaults, conf.API.Domain+"/assets/v1/"))
} }
if *authEnabled { if *authEnabled {
apis.RegisterServer(ctx, auth.CreateServer(command, query, authRepo, conf.SystemDefaults, conf.Auth.APIDomain+"/assets/v1/")) apis.RegisterServer(ctx, auth.CreateServer(command, query, authRepo, conf.SystemDefaults, conf.API.Domain+"/assets/v1/"))
} }
if *oidcEnabled { if *oidcEnabled {
op := oidc.NewProvider(ctx, conf.API.OIDC, command, query, authRepo, conf.SystemDefaults.KeyConfig, *localDevMode, es, projections, keyChan, conf.Mgmt.APIDomain+"/assets/v1/") op := oidc.NewProvider(ctx, conf.API.OIDC, command, query, authRepo, conf.SystemDefaults.KeyConfig, *localDevMode, es, projections, keyChan, conf.API.Domain+"/assets/v1/")
apis.RegisterHandler("/oauth/v2", op.HttpHandler()) apis.RegisterHandler("/oauth/v2", op.HttpHandler())
} }
if *assetsEnabled { if *assetsEnabled {
assetsHandler := assets.NewHandler(command, verifier, conf.InternalAuthZ, id.SonyFlakeGenerator, static, managementRepo, query) assetsHandler := assets.NewHandler(command, verifier, conf.InternalAuthZ, id.SonyFlakeGenerator, static, query)
apis.RegisterHandler("/assets/v1", assetsHandler) apis.RegisterHandler("/assets/v1", assetsHandler)
} }

View File

@ -246,53 +246,8 @@ Admin:
BulkLimit: 10000 BulkLimit: 10000
FailureCountUntilSkip: 5 FailureCountUntilSkip: 5
Mgmt:
SearchLimit: 1000
Domain: $ZITADEL_DEFAULT_DOMAIN
APIDomain: $ZITADEL_API_DOMAIN
Eventstore:
ServiceName: 'ManagementAPI'
Repository:
SQL:
Host: $ZITADEL_EVENTSTORE_HOST
Port: $ZITADEL_EVENTSTORE_PORT
User: 'management'
Database: 'eventstore'
Password: $CR_MANAGEMENT_PASSWORD
MaxOpenConns: 3
MaxConnLifetime: 30m
MaxConnIdleTime: 30m
Options: $CR_OPTIONS
SSL:
Mode: $CR_SSL_MODE
RootCert: $CR_ROOT_CERT
Cert: $CR_MANAGEMENT_CERT
Key: $CR_MANAGEMENT_KEY
Cache:
Type: 'fastcache'
Config:
MaxCacheSizeInByte: 10485760 #10mb
View:
Host: $ZITADEL_EVENTSTORE_HOST
Port: $ZITADEL_EVENTSTORE_PORT
User: 'management'
Options: $CR_OPTIONS
Database: 'management'
Password: $CR_MANAGEMENT_PASSWORD
MaxOpenConns: 3
MaxConnLifetime: 30m
MaxConnIdleTime: 30m
SSL:
Mode: $CR_SSL_MODE
RootCert: $CR_ROOT_CERT
Cert: $CR_MANAGEMENT_CERT
Key: $CR_MANAGEMENT_KEY
Spooler:
ConcurrentWorkers: 1
BulkLimit: 10000
FailureCountUntilSkip: 5
API: API:
Domain: $ZITADEL_API_DOMAIN
GRPC: GRPC:
ServerPort: 50001 ServerPort: 50001
GatewayPort: 50002 GatewayPort: 50002

View File

@ -1042,8 +1042,7 @@ This is an empty request
| Field | Type | Description | Validation | | Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ListDetails | - | | | result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
| result | repeated zitadel.change.v1.Change | - | |

View File

@ -5179,8 +5179,7 @@ This is an empty response
| Field | Type | Description | Validation | | Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ListDetails | - | | | result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
| result | repeated zitadel.change.v1.Change | - | |
@ -5453,8 +5452,7 @@ This is an empty response
| Field | Type | Description | Validation | | Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ListDetails | - | | | result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
| result | repeated zitadel.change.v1.Change | - | |
@ -5568,8 +5566,7 @@ This is an empty request
| Field | Type | Description | Validation | | Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ListDetails | - | | | result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
| result | repeated zitadel.change.v1.Change | - | |
@ -5759,8 +5756,7 @@ This is an empty request
| Field | Type | Description | Validation | | Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ListDetails | - | | | result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
| result | repeated zitadel.change.v1.Change | - | |

View File

@ -1,55 +0,0 @@
package eventstore
import (
"context"
"net/http"
"strings"
"sync"
"github.com/caos/logging"
"golang.org/x/text/language"
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/config/systemdefaults"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/query"
)
type IAMRepository struct {
Query *query.Queries
Eventstore v1.Eventstore
SearchLimit uint64
View *admin_view.View
SystemDefaults systemdefaults.SystemDefaults
Roles []string
PrefixAvatarURL string
LoginDir http.FileSystem
NotificationDir http.FileSystem
LoginTranslationFileContents map[string][]byte
NotificationTranslationFileContents map[string][]byte
mutex sync.Mutex
supportedLangs []language.Tag
}
func (repo *IAMRepository) Languages(ctx context.Context) ([]language.Tag, error) {
if len(repo.supportedLangs) == 0 {
langs, err := i18n.SupportedLanguages(repo.LoginDir)
if err != nil {
logging.Log("ADMIN-tiMWs").WithError(err).Debug("unable to parse language")
return nil, err
}
repo.supportedLangs = langs
}
return repo.supportedLangs, nil
}
func (repo *IAMRepository) GetIAMMemberRoles() []string {
roles := make([]string, 0)
for _, roleMap := range repo.Roles {
if strings.HasPrefix(roleMap, "IAM") {
roles = append(roles, roleMap)
}
}
return roles
}

View File

@ -3,9 +3,6 @@ package eventsourcing
import ( import (
"context" "context"
"github.com/caos/logging"
"github.com/rakyll/statik/fs"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore" "github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/spooler" "github.com/caos/zitadel/internal/admin/repository/eventsourcing/spooler"
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view" admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
@ -28,11 +25,10 @@ type Config struct {
type EsRepository struct { type EsRepository struct {
spooler *es_spol.Spooler spooler *es_spol.Spooler
eventstore.IAMRepository
eventstore.AdministratorRepo eventstore.AdministratorRepo
} }
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, static static.Storage, roles []string, localDevMode bool) (*EsRepository, error) { func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, static static.Storage, localDevMode bool) (*EsRepository, error) {
es, err := v1.Start(conf.Eventstore) es, err := v1.Start(conf.Eventstore)
if err != nil { if err != nil {
return nil, err return nil, err
@ -47,28 +43,9 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, c
} }
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, command, static, localDevMode) spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, command, static, localDevMode)
assetsAPI := conf.APIDomain + "/assets/v1/"
statikLoginFS, err := fs.NewWithNamespace("login")
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start login statik dir")
statikNotificationFS, err := fs.NewWithNamespace("notification")
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start notification statik dir")
return &EsRepository{ return &EsRepository{
spooler: spool, spooler: spool,
IAMRepository: eventstore.IAMRepository{
Eventstore: es,
View: view,
SystemDefaults: systemDefaults,
SearchLimit: conf.SearchLimit,
Roles: roles,
PrefixAvatarURL: assetsAPI,
LoginDir: statikLoginFS,
NotificationDir: statikNotificationFS,
LoginTranslationFileContents: make(map[string][]byte),
NotificationTranslationFileContents: make(map[string][]byte),
},
AdministratorRepo: eventstore.AdministratorRepo{ AdministratorRepo: eventstore.AdministratorRepo{
View: view, View: view,
}, },

View File

@ -1,13 +0,0 @@
package repository
import (
"context"
"golang.org/x/text/language"
)
type IAMRepository interface {
Languages(ctx context.Context) ([]language.Tag, error)
GetIAMMemberRoles() []string
}

View File

@ -4,6 +4,5 @@ import "context"
type Repository interface { type Repository interface {
Health(ctx context.Context) error Health(ctx context.Context) error
IAMRepository
AdministratorRepository AdministratorRepository
} }

View File

@ -17,7 +17,7 @@ import (
http_util "github.com/caos/zitadel/internal/api/http" http_util "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/api/oidc" "github.com/caos/zitadel/internal/api/oidc"
auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing" auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
authz_es "github.com/caos/zitadel/internal/authz/repository/eventsourcing" authz_repo "github.com/caos/zitadel/internal/authz/repository"
"github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
@ -29,8 +29,9 @@ import (
) )
type Config struct { type Config struct {
GRPC grpc_util.Config GRPC grpc_util.Config
OIDC oidc.OPHandlerConfig OIDC oidc.OPHandlerConfig
Domain string
} }
type API struct { type API struct {
@ -58,16 +59,16 @@ type admin interface {
GetSpoolerDiv(database, viewName string) int64 GetSpoolerDiv(database, viewName string) int64
} }
func Create(config Config, authZ authz.Config, q *query.Queries, authZRepo *authz_es.EsRepository, authRepo *auth_es.EsRepository, adminRepo *admin_es.EsRepository, sd systemdefaults.SystemDefaults) *API { func Create(config Config, authZ authz.Config, q *query.Queries, authZRepo authz_repo.Repository, authRepo *auth_es.EsRepository, adminRepo *admin_es.EsRepository, sd systemdefaults.SystemDefaults) *API {
api := &API{ api := &API{
serverPort: config.GRPC.ServerPort, serverPort: config.GRPC.ServerPort,
} }
repo := struct { repo := struct {
authz_es.EsRepository authz_repo.Repository
query.Queries query.Queries
}{ }{
*authZRepo, authZRepo,
*q, *q,
} }

View File

@ -17,7 +17,6 @@ import (
"github.com/caos/zitadel/internal/command" "github.com/caos/zitadel/internal/command"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
"github.com/caos/zitadel/internal/management/repository"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/static" "github.com/caos/zitadel/internal/static"
) )
@ -28,7 +27,6 @@ type Handler struct {
commands *command.Commands commands *command.Commands
authInterceptor *http_mw.AuthInterceptor authInterceptor *http_mw.AuthInterceptor
idGenerator id.Generator idGenerator id.Generator
orgRepo repository.OrgRepository
query *query.Queries query *query.Queries
} }
@ -74,7 +72,6 @@ func NewHandler(
authConfig authz.Config, authConfig authz.Config,
idGenerator id.Generator, idGenerator id.Generator,
storage static.Storage, storage static.Storage,
orgRepo repository.OrgRepository,
queries *query.Queries, queries *query.Queries,
) http.Handler { ) http.Handler {
h := &Handler{ h := &Handler{
@ -83,7 +80,6 @@ func NewHandler(
authInterceptor: http_mw.AuthorizationInterceptor(verifier, authConfig), authInterceptor: http_mw.AuthorizationInterceptor(verifier, authConfig),
idGenerator: idGenerator, idGenerator: idGenerator,
storage: storage, storage: storage,
orgRepo: orgRepo,
query: queries, query: queries,
} }

View File

@ -10,7 +10,7 @@ import (
) )
func (s *Server) ListIAMMemberRoles(ctx context.Context, req *admin_pb.ListIAMMemberRolesRequest) (*admin_pb.ListIAMMemberRolesResponse, error) { func (s *Server) ListIAMMemberRoles(ctx context.Context, req *admin_pb.ListIAMMemberRolesRequest) (*admin_pb.ListIAMMemberRolesResponse, error) {
roles := s.iam.GetIAMMemberRoles() roles := s.query.GetIAMMemberRoles()
return &admin_pb.ListIAMMemberRolesResponse{ return &admin_pb.ListIAMMemberRolesResponse{
Roles: roles, Roles: roles,
Details: object.ToListDetails(uint64(len(roles)), 0, time.Now()), Details: object.ToListDetails(uint64(len(roles)), 0, time.Now()),

View File

@ -8,7 +8,7 @@ import (
) )
func (s *Server) GetSupportedLanguages(ctx context.Context, req *admin_pb.GetSupportedLanguagesRequest) (*admin_pb.GetSupportedLanguagesResponse, error) { func (s *Server) GetSupportedLanguages(ctx context.Context, req *admin_pb.GetSupportedLanguagesRequest) (*admin_pb.GetSupportedLanguagesResponse, error) {
langs, err := s.iam.Languages(ctx) langs, err := s.query.Languages(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -22,7 +22,6 @@ type Server struct {
admin.UnimplementedAdminServiceServer admin.UnimplementedAdminServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
iam repository.IAMRepository
administrator repository.AdministratorRepository administrator repository.AdministratorRepository
iamDomain string iamDomain string
assetsAPIDomain string assetsAPIDomain string
@ -36,7 +35,6 @@ func CreateServer(command *command.Commands, query *query.Queries, repo reposito
return &Server{ return &Server{
command: command, command: command,
query: query, query: query,
iam: repo,
administrator: repo, administrator: repo,
iamDomain: iamDomain, iamDomain: iamDomain,
assetsAPIDomain: assetsAPIDomain, assetsAPIDomain: assetsAPIDomain,

View File

@ -3,28 +3,43 @@ package auth
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/api/authz"
obj_grpc "github.com/caos/zitadel/internal/api/grpc/object" obj_grpc "github.com/caos/zitadel/internal/api/grpc/object"
user_grpc "github.com/caos/zitadel/internal/api/grpc/user" user_grpc "github.com/caos/zitadel/internal/api/grpc/user"
"github.com/caos/zitadel/internal/query"
auth_pb "github.com/caos/zitadel/pkg/grpc/auth" auth_pb "github.com/caos/zitadel/pkg/grpc/auth"
) )
func (s *Server) ListMyZitadelPermissions(ctx context.Context, _ *auth_pb.ListMyZitadelPermissionsRequest) (*auth_pb.ListMyZitadelPermissionsResponse, error) { func (s *Server) ListMyZitadelPermissions(ctx context.Context, _ *auth_pb.ListMyZitadelPermissionsRequest) (*auth_pb.ListMyZitadelPermissionsResponse, error) {
perms, err := s.repo.SearchMyZitadelPermissions(ctx) perms, err := s.query.MyZitadelPermissions(ctx, authz.GetCtxData(ctx).UserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &auth_pb.ListMyZitadelPermissionsResponse{ return &auth_pb.ListMyZitadelPermissionsResponse{
Result: perms, Result: perms.Permissions,
}, nil }, nil
} }
func (s *Server) ListMyProjectPermissions(ctx context.Context, _ *auth_pb.ListMyProjectPermissionsRequest) (*auth_pb.ListMyProjectPermissionsResponse, error) { func (s *Server) ListMyProjectPermissions(ctx context.Context, _ *auth_pb.ListMyProjectPermissionsRequest) (*auth_pb.ListMyProjectPermissionsResponse, error) {
perms, err := s.repo.SearchMyProjectPermissions(ctx) ctxData := authz.GetCtxData(ctx)
userGrantOrgID, err := query.NewUserGrantResourceOwnerSearchQuery(ctxData.OrgID)
if err != nil {
return nil, err
}
userGrantProjectID, err := query.NewUserGrantProjectIDSearchQuery(ctxData.ProjectID)
if err != nil {
return nil, err
}
userGrantUserID, err := query.NewUserGrantUserIDSearchQuery(ctxData.UserID)
if err != nil {
return nil, err
}
userGrant, err := s.query.UserGrant(ctx, userGrantOrgID, userGrantProjectID, userGrantUserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &auth_pb.ListMyProjectPermissionsResponse{ return &auth_pb.ListMyProjectPermissionsResponse{
Result: perms, Result: userGrant.Roles,
}, nil }, nil
} }

View File

@ -12,7 +12,6 @@ import (
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore/v1/models" "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
auth_pb "github.com/caos/zitadel/pkg/grpc/auth" auth_pb "github.com/caos/zitadel/pkg/grpc/auth"
) )
@ -26,7 +25,12 @@ func (s *Server) GetMyUser(ctx context.Context, _ *auth_pb.GetMyUserRequest) (*a
func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserRequest) (*auth_pb.RemoveMyUserResponse, error) { func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserRequest) (*auth_pb.RemoveMyUserResponse, error) {
ctxData := authz.GetCtxData(ctx) ctxData := authz.GetCtxData(ctx)
grants, err := s.repo.SearchMyUserGrants(ctx, &grant_model.UserGrantSearchRequest{Queries: []*grant_model.UserGrantSearchQuery{}}) userGrantUserID, err := query.NewUserGrantUserIDSearchQuery(ctxData.UserID)
if err != nil {
return nil, err
}
queries := &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantUserID}}
grants, err := s.query.UserGrants(ctx, queries)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,7 +45,7 @@ func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserReques
if err != nil { if err != nil {
return nil, err return nil, err
} }
details, err := s.command.RemoveUser(ctx, ctxData.UserID, ctxData.ResourceOwner, memberships.Memberships, userGrantsToIDs(grants.Result)...) details, err := s.command.RemoveUser(ctx, ctxData.UserID, ctxData.ResourceOwner, memberships.Memberships, userGrantsToIDs(grants.UserGrants)...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,17 +55,17 @@ func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserReques
} }
func (s *Server) ListMyUserChanges(ctx context.Context, req *auth_pb.ListMyUserChangesRequest) (*auth_pb.ListMyUserChangesResponse, error) { func (s *Server) ListMyUserChanges(ctx context.Context, req *auth_pb.ListMyUserChangesRequest) (*auth_pb.ListMyUserChangesResponse, error) {
sequence, limit, asc := change.ChangeQueryToModel(req.Query) sequence, limit, asc := change.ChangeQueryToQuery(req.Query)
features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).ResourceOwner) features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).ResourceOwner)
if err != nil { if err != nil {
return nil, err return nil, err
} }
changes, err := s.repo.MyUserChanges(ctx, sequence, limit, asc, features.AuditLogRetention) changes, err := s.query.UserChanges(ctx, authz.GetCtxData(ctx).UserID, sequence, limit, asc, features.AuditLogRetention)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &auth_pb.ListMyUserChangesResponse{ return &auth_pb.ListMyUserChangesResponse{
Result: change.UserChangesToPb(changes.Changes), Result: change.ChangesToPb(changes.Changes, s.assetsAPIDomain),
}, nil }, nil
} }
@ -124,14 +128,18 @@ func ctxToObjectRoot(ctx context.Context) models.ObjectRoot {
} }
func (s *Server) ListMyUserGrants(ctx context.Context, req *auth_pb.ListMyUserGrantsRequest) (*auth_pb.ListMyUserGrantsResponse, error) { func (s *Server) ListMyUserGrants(ctx context.Context, req *auth_pb.ListMyUserGrantsRequest) (*auth_pb.ListMyUserGrantsResponse, error) {
res, err := s.repo.SearchMyUserGrants(ctx, ListMyUserGrantsRequestToModel(req)) queries, err := ListMyUserGrantsRequestToQuery(ctx, req)
if err != nil {
return nil, err
}
res, err := s.query.UserGrants(ctx, queries)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &auth_pb.ListMyUserGrantsResponse{ return &auth_pb.ListMyUserGrantsResponse{
Result: UserGrantsToPb(res.Result), Result: UserGrantsToPb(res.UserGrants),
Details: obj_grpc.ToListDetails( Details: obj_grpc.ToListDetails(
res.TotalResult, res.Count,
res.Sequence, res.Sequence,
res.Timestamp, res.Timestamp,
), ),
@ -152,13 +160,21 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje
//client of user is not in project of ZITADEL //client of user is not in project of ZITADEL
if ctxData.ProjectID != iam.IAMProjectID { if ctxData.ProjectID != iam.IAMProjectID {
grants, err := s.repo.UserGrantsByProjectAndUserID(ctxData.ProjectID, ctxData.UserID) userGrantProjectID, err := query.NewUserGrantProjectIDSearchQuery(ctxData.ProjectID)
if err != nil {
return nil, err
}
userGrantUserID, err := query.NewUserGrantUserIDSearchQuery(ctxData.UserID)
if err != nil {
return nil, err
}
grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantProjectID, userGrantUserID}})
if err != nil { if err != nil {
return nil, err return nil, err
} }
ids := make([]string, 0, len(grants)) ids := make([]string, 0, len(grants.UserGrants))
for _, grant := range grants { for _, grant := range grants.UserGrants {
ids = appendIfNotExists(ids, grant.ResourceOwner) ids = appendIfNotExists(ids, grant.ResourceOwner)
} }
@ -276,7 +292,7 @@ func MemberTypeToDomain(m *query.Membership) (_ domain.MemberType, displayName,
return domain.MemberTypeUnspecified, "", "", "" return domain.MemberTypeUnspecified, "", "", ""
} }
func userGrantsToIDs(userGrants []*grant_model.UserGrantView) []string { func userGrantsToIDs(userGrants []*query.UserGrant) []string {
converted := make([]string, len(userGrants)) converted := make([]string, len(userGrants))
for i, grant := range userGrants { for i, grant := range userGrants {
converted[i] = grant.ID converted[i] = grant.ID

View File

@ -1,21 +1,33 @@
package auth package auth
import ( import (
"context"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/grpc/object" "github.com/caos/zitadel/internal/api/grpc/object"
"github.com/caos/zitadel/internal/usergrant/model" "github.com/caos/zitadel/internal/query"
auth_pb "github.com/caos/zitadel/pkg/grpc/auth" auth_pb "github.com/caos/zitadel/pkg/grpc/auth"
) )
func ListMyUserGrantsRequestToModel(req *auth_pb.ListMyUserGrantsRequest) *model.UserGrantSearchRequest { func ListMyUserGrantsRequestToQuery(ctx context.Context, req *auth_pb.ListMyUserGrantsRequest) (*query.UserGrantsQueries, error) {
offset, limit, asc := object.ListQueryToModel(req.Query) offset, limit, asc := object.ListQueryToModel(req.Query)
return &model.UserGrantSearchRequest{ userGrantUserID, err := query.NewUserGrantUserIDSearchQuery(authz.GetCtxData(ctx).UserID)
Offset: offset, if err != nil {
Limit: limit, return nil, err
Asc: asc,
} }
return &query.UserGrantsQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
},
Queries: []query.SearchQuery{
userGrantUserID,
},
}, nil
} }
func UserGrantsToPb(grants []*model.UserGrantView) []*auth_pb.UserGrant { func UserGrantsToPb(grants []*query.UserGrant) []*auth_pb.UserGrant {
userGrants := make([]*auth_pb.UserGrant, len(grants)) userGrants := make([]*auth_pb.UserGrant, len(grants))
for i, grant := range grants { for i, grant := range grants {
userGrants[i] = UserGrantToPb(grant) userGrants[i] = UserGrantToPb(grant)
@ -23,13 +35,13 @@ func UserGrantsToPb(grants []*model.UserGrantView) []*auth_pb.UserGrant {
return userGrants return userGrants
} }
func UserGrantToPb(grant *model.UserGrantView) *auth_pb.UserGrant { func UserGrantToPb(grant *query.UserGrant) *auth_pb.UserGrant {
return &auth_pb.UserGrant{ return &auth_pb.UserGrant{
GrantId: grant.ID, GrantId: grant.ID,
OrgId: grant.ResourceOwner, OrgId: grant.ResourceOwner,
OrgName: grant.OrgName, OrgName: grant.OrgName,
ProjectId: grant.ProjectID, ProjectId: grant.ProjectID,
UserId: grant.UserID, UserId: grant.UserID,
Roles: grant.RoleKeys, Roles: grant.Roles,
} }
} }

View File

@ -1,100 +1,39 @@
package change package change
import ( import (
org_model "github.com/caos/zitadel/internal/org/model" "google.golang.org/protobuf/types/known/timestamppb"
proj_model "github.com/caos/zitadel/internal/project/model"
user_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/query"
change_pb "github.com/caos/zitadel/pkg/grpc/change" change_pb "github.com/caos/zitadel/pkg/grpc/change"
"github.com/caos/zitadel/pkg/grpc/message" "github.com/caos/zitadel/pkg/grpc/message"
) )
func ChangeQueryToModel(query *change_pb.ChangeQuery) (sequence uint64, limit uint64, asc bool) { func ChangeQueryToQuery(query *change_pb.ChangeQuery) (sequence uint64, limit uint64, asc bool) {
if query == nil { if query == nil {
return 0, 0, false return 0, 0, false
} }
return query.Sequence, uint64(query.Limit), query.Asc return query.Sequence, uint64(query.Limit), query.Asc
} }
func UserChangesToPb(changes []*user_model.UserChange) []*change_pb.Change { func ChangesToPb(changes []*query.Change, assetAPIPrefix string) []*change_pb.Change {
c := make([]*change_pb.Change, len(changes)) c := make([]*change_pb.Change, len(changes))
for i, change := range changes { for i, change := range changes {
c[i] = UserChangeToPb(change) c[i] = ChangeToPb(change, assetAPIPrefix)
} }
return c return c
} }
func UserChangeToPb(change *user_model.UserChange) *change_pb.Change { func ChangeToPb(change *query.Change, assetAPIPrefix string) *change_pb.Change {
return &change_pb.Change{ return &change_pb.Change{
ChangeDate: change.ChangeDate, ChangeDate: timestamppb.New(change.ChangeDate),
EventType: message.NewLocalizedEventType(change.EventType),
Sequence: change.Sequence,
EditorId: change.ModifierID,
EditorDisplayName: change.ModifierName,
EditorPreferredLoginName: change.ModifierLoginName,
EditorAvatarUrl: change.ModifierAvatarURL,
// ResourceOwnerId: change.,TODO: resource owner not returned
}
}
func OrgChangesToPb(changes []*org_model.OrgChange) []*change_pb.Change {
c := make([]*change_pb.Change, len(changes))
for i, change := range changes {
c[i] = OrgChangeToPb(change)
}
return c
}
func OrgChangeToPb(change *org_model.OrgChange) *change_pb.Change {
return &change_pb.Change{
ChangeDate: change.ChangeDate,
EventType: message.NewLocalizedEventType(change.EventType), EventType: message.NewLocalizedEventType(change.EventType),
Sequence: change.Sequence, Sequence: change.Sequence,
EditorId: change.ModifierId, EditorId: change.ModifierId,
EditorDisplayName: change.ModifierName, EditorDisplayName: change.ModifierName,
EditorPreferredLoginName: change.ModifierLoginName, EditorPreferredLoginName: change.ModifierLoginName,
EditorAvatarUrl: change.ModifierAvatarURL, EditorAvatarUrl: domain.AvatarURL(assetAPIPrefix, change.ModifierResourceOwner, change.ModifierAvatarKey),
// ResourceOwnerId: change.,TODO: resource owner not returned ResourceOwnerId: change.ResourceOwner,
}
}
func ProjectChangesToPb(changes []*proj_model.ProjectChange) []*change_pb.Change {
c := make([]*change_pb.Change, len(changes))
for i, change := range changes {
c[i] = ProjectChangeToPb(change)
}
return c
}
func ProjectChangeToPb(change *proj_model.ProjectChange) *change_pb.Change {
return &change_pb.Change{
ChangeDate: change.ChangeDate,
EventType: message.NewLocalizedEventType(change.EventType),
Sequence: change.Sequence,
EditorId: change.ModifierId,
EditorDisplayName: change.ModifierName,
EditorPreferredLoginName: change.ModifierLoginName,
EditorAvatarUrl: change.ModifierAvatarURL,
// ResourceOwnerId: change.,TODO: resource owner not returned
}
}
func AppChangesToPb(changes []*proj_model.ApplicationChange) []*change_pb.Change {
c := make([]*change_pb.Change, len(changes))
for i, change := range changes {
c[i] = AppChangeToPb(change)
}
return c
}
func AppChangeToPb(change *proj_model.ApplicationChange) *change_pb.Change {
return &change_pb.Change{
ChangeDate: change.ChangeDate,
EventType: message.NewLocalizedEventType(change.EventType),
Sequence: change.Sequence,
EditorId: change.ModifierId,
EditorDisplayName: change.ModifierName,
EditorPreferredLoginName: change.ModifierLoginName,
EditorAvatarUrl: change.ModifierAvatarURL,
// ResourceOwnerId: change.,TODO: resource owner not returned
} }
} }

View File

@ -33,17 +33,17 @@ func (s *Server) GetOrgByDomainGlobal(ctx context.Context, req *mgmt_pb.GetOrgBy
} }
func (s *Server) ListOrgChanges(ctx context.Context, req *mgmt_pb.ListOrgChangesRequest) (*mgmt_pb.ListOrgChangesResponse, error) { func (s *Server) ListOrgChanges(ctx context.Context, req *mgmt_pb.ListOrgChangesRequest) (*mgmt_pb.ListOrgChangesResponse, error) {
sequence, limit, asc := change_grpc.ChangeQueryToModel(req.Query) sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query)
features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
response, err := s.org.OrgChanges(ctx, authz.GetCtxData(ctx).OrgID, sequence, limit, asc, features.AuditLogRetention) response, err := s.query.OrgChanges(ctx, authz.GetCtxData(ctx).OrgID, sequence, limit, asc, features.AuditLogRetention)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &mgmt_pb.ListOrgChangesResponse{ return &mgmt_pb.ListOrgChangesResponse{
Result: change_grpc.OrgChangesToPb(response.Changes), Result: change_grpc.ChangesToPb(response.Changes, s.assetAPIPrefix),
}, nil }, nil
} }
@ -211,7 +211,7 @@ func (s *Server) ListOrgMemberRoles(ctx context.Context, req *mgmt_pb.ListOrgMem
if err != nil { if err != nil {
return nil, err return nil, err
} }
roles := s.org.GetOrgMemberRoles(authz.GetCtxData(ctx).OrgID == iam.GlobalOrgID) roles := s.query.GetOrgMemberRoles(authz.GetCtxData(ctx).OrgID == iam.GlobalOrgID)
return &mgmt_pb.ListOrgMemberRolesResponse{ return &mgmt_pb.ListOrgMemberRolesResponse{
Result: roles, Result: roles,
}, nil }, nil

View File

@ -110,17 +110,17 @@ func (s *Server) ListGrantedProjectRoles(ctx context.Context, req *mgmt_pb.ListG
} }
func (s *Server) ListProjectChanges(ctx context.Context, req *mgmt_pb.ListProjectChangesRequest) (*mgmt_pb.ListProjectChangesResponse, error) { func (s *Server) ListProjectChanges(ctx context.Context, req *mgmt_pb.ListProjectChangesRequest) (*mgmt_pb.ListProjectChangesResponse, error) {
sequence, limit, asc := change_grpc.ChangeQueryToModel(req.Query) sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query)
features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
res, err := s.project.ProjectChanges(ctx, req.ProjectId, sequence, limit, asc, features.AuditLogRetention) res, err := s.query.ProjectChanges(ctx, req.ProjectId, sequence, limit, asc, features.AuditLogRetention)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &mgmt_pb.ListProjectChangesResponse{ return &mgmt_pb.ListProjectChangesResponse{
Result: change_grpc.ProjectChangesToPb(res.Changes), Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix),
}, nil }, nil
} }
@ -289,7 +289,7 @@ func (s *Server) RemoveProjectRole(ctx context.Context, req *mgmt_pb.RemoveProje
} }
func (s *Server) ListProjectMemberRoles(ctx context.Context, _ *mgmt_pb.ListProjectMemberRolesRequest) (*mgmt_pb.ListProjectMemberRolesResponse, error) { func (s *Server) ListProjectMemberRoles(ctx context.Context, _ *mgmt_pb.ListProjectMemberRolesRequest) (*mgmt_pb.ListProjectMemberRolesResponse, error) {
roles, err := s.project.GetProjectMemberRoles(ctx) roles, err := s.query.GetProjectMemberRoles(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -42,17 +42,17 @@ func (s *Server) ListApps(ctx context.Context, req *mgmt_pb.ListAppsRequest) (*m
} }
func (s *Server) ListAppChanges(ctx context.Context, req *mgmt_pb.ListAppChangesRequest) (*mgmt_pb.ListAppChangesResponse, error) { func (s *Server) ListAppChanges(ctx context.Context, req *mgmt_pb.ListAppChangesRequest) (*mgmt_pb.ListAppChangesResponse, error) {
sequence, limit, asc := change_grpc.ChangeQueryToModel(req.Query) sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query)
features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
res, err := s.project.ApplicationChanges(ctx, req.ProjectId, req.AppId, sequence, limit, asc, features.AuditLogRetention) res, err := s.query.ApplicationChanges(ctx, req.ProjectId, req.AppId, sequence, limit, asc, features.AuditLogRetention)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &mgmt_pb.ListAppChangesResponse{ return &mgmt_pb.ListAppChangesResponse{
Result: change_grpc.AppChangesToPb(res.Changes), Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix),
}, nil }, nil
} }

View File

@ -160,7 +160,7 @@ func (s *Server) RemoveProjectGrant(ctx context.Context, req *mgmt_pb.RemoveProj
} }
func (s *Server) ListProjectGrantMemberRoles(ctx context.Context, req *mgmt_pb.ListProjectGrantMemberRolesRequest) (*mgmt_pb.ListProjectGrantMemberRolesResponse, error) { func (s *Server) ListProjectGrantMemberRoles(ctx context.Context, req *mgmt_pb.ListProjectGrantMemberRolesRequest) (*mgmt_pb.ListProjectGrantMemberRolesResponse, error) {
roles := s.project.GetProjectGrantMemberRoles() roles := s.query.GetProjectGrantMemberRoles()
return &mgmt_pb.ListProjectGrantMemberRolesResponse{ return &mgmt_pb.ListProjectGrantMemberRolesResponse{
Result: roles, Result: roles,
Details: object_grpc.ToListDetails(uint64(len(roles)), 0, time.Now()), Details: object_grpc.ToListDetails(uint64(len(roles)), 0, time.Now()),

View File

@ -7,8 +7,6 @@ import (
"github.com/caos/zitadel/internal/api/grpc/server" "github.com/caos/zitadel/internal/api/grpc/server"
"github.com/caos/zitadel/internal/command" "github.com/caos/zitadel/internal/command"
"github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/management/repository"
"github.com/caos/zitadel/internal/management/repository/eventsourcing"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/pkg/grpc/management" "github.com/caos/zitadel/pkg/grpc/management"
) )
@ -23,24 +21,14 @@ type Server struct {
management.UnimplementedManagementServiceServer management.UnimplementedManagementServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
project repository.ProjectRepository
org repository.OrgRepository
user repository.UserRepository
systemDefaults systemdefaults.SystemDefaults systemDefaults systemdefaults.SystemDefaults
assetAPIPrefix string assetAPIPrefix string
} }
type Config struct { func CreateServer(command *command.Commands, query *query.Queries, sd systemdefaults.SystemDefaults, assetAPIPrefix string) *Server {
Repository eventsourcing.Config
}
func CreateServer(command *command.Commands, query *query.Queries, repo repository.Repository, sd systemdefaults.SystemDefaults, assetAPIPrefix string) *Server {
return &Server{ return &Server{
command: command, command: command,
query: query, query: query,
project: repo,
org: repo,
user: repo,
systemDefaults: sd, systemDefaults: sd,
assetAPIPrefix: assetAPIPrefix, assetAPIPrefix: assetAPIPrefix,
} }

View File

@ -70,17 +70,17 @@ func (s *Server) ListUsers(ctx context.Context, req *mgmt_pb.ListUsersRequest) (
} }
func (s *Server) ListUserChanges(ctx context.Context, req *mgmt_pb.ListUserChangesRequest) (*mgmt_pb.ListUserChangesResponse, error) { func (s *Server) ListUserChanges(ctx context.Context, req *mgmt_pb.ListUserChangesRequest) (*mgmt_pb.ListUserChangesResponse, error) {
sequence, limit, asc := change_grpc.ChangeQueryToModel(req.Query) sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query)
features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
res, err := s.user.UserChanges(ctx, req.UserId, sequence, limit, asc, features.AuditLogRetention) res, err := s.query.UserChanges(ctx, req.UserId, sequence, limit, asc, features.AuditLogRetention)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &mgmt_pb.ListUserChangesResponse{ return &mgmt_pb.ListUserChangesResponse{
Result: change_grpc.UserChangesToPb(res.Changes), Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix),
}, nil }, nil
} }

View File

@ -11,11 +11,15 @@ import (
) )
func (s *Server) GetUserGrantByID(ctx context.Context, req *mgmt_pb.GetUserGrantByIDRequest) (*mgmt_pb.GetUserGrantByIDResponse, error) { func (s *Server) GetUserGrantByID(ctx context.Context, req *mgmt_pb.GetUserGrantByIDRequest) (*mgmt_pb.GetUserGrantByIDResponse, error) {
idQuery, err := query.NewUserGrantGrantIDSearchQuery(req.GrantId)
if err != nil {
return nil, err
}
ownerQuery, err := query.NewUserGrantResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID) ownerQuery, err := query.NewUserGrantResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
grant, err := s.query.UserGrantByID(ctx, req.GrantId, ownerQuery) grant, err := s.query.UserGrant(ctx, idQuery, ownerQuery)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,7 +17,6 @@ import (
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
) )
const ( const (
@ -108,7 +107,14 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr
UserID: oidcCtx, UserID: oidcCtx,
OrgID: oidcCtx, OrgID: oidcCtx,
}) })
return o.repo.AuthorizeClientIDSecret(ctx, id, secret) app, err := o.query.AppByClientID(ctx, id)
if err != nil {
return err
}
if app.OIDCConfig != nil {
return o.command.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret)
}
return o.command.VerifyAPIClientSecret(ctx, app.ProjectID, app.ID, secret)
} }
func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.UserInfoSetter, tokenID, subject, origin string) (err error) { func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.UserInfoSetter, tokenID, subject, origin string) (err error) {
@ -293,13 +299,23 @@ func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID strin
if err != nil { if err != nil {
return nil, err return nil, err
} }
grants, err := o.repo.UserGrantsByProjectAndUserID(projectID, userID) projectQuery, err := query.NewUserGrantProjectIDSearchQuery(projectID)
if err != nil {
return nil, err
}
userIDQuery, err := query.NewUserGrantUserIDSearchQuery(userID)
if err != nil {
return nil, err
}
grants, err := o.query.UserGrants(ctx, &query.UserGrantsQueries{
Queries: []query.SearchQuery{projectQuery, userIDQuery},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
projectRoles := make(map[string]map[string]string) projectRoles := make(map[string]map[string]string)
for _, requestedRole := range requestedRoles { for _, requestedRole := range requestedRoles {
for _, grant := range grants { for _, grant := range grants.UserGrants {
checkGrantedRoles(projectRoles, grant, requestedRole) checkGrantedRoles(projectRoles, grant, requestedRole)
} }
} }
@ -335,8 +351,8 @@ func (o *OPStorage) assertUserResourceOwner(ctx context.Context, userID string)
}, nil }, nil
} }
func checkGrantedRoles(roles map[string]map[string]string, grant *grant_model.UserGrantView, requestedRole string) { func checkGrantedRoles(roles map[string]map[string]string, grant *query.UserGrant, requestedRole string) {
for _, grantedRole := range grant.RoleKeys { for _, grantedRole := range grant.Roles {
if requestedRole == grantedRole { if requestedRole == grantedRole {
appendRole(roles, grantedRole, grant.ResourceOwner, grant.OrgPrimaryDomain) appendRole(roles, grantedRole, grant.ResourceOwner, grant.OrgPrimaryDomain)
} }

View File

@ -1,9 +0,0 @@
package repository
import (
"context"
)
type ApplicationRepository interface {
AuthorizeClientIDSecret(ctx context.Context, clientID, secret string) error
}

View File

@ -1,28 +0,0 @@
package eventstore
import (
"context"
"github.com/caos/zitadel/internal/command"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/telemetry/tracing"
)
type ApplicationRepo struct {
Commands *command.Commands
Query *query.Queries
}
func (a *ApplicationRepo) AuthorizeClientIDSecret(ctx context.Context, clientID, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
app, err := a.Query.AppByClientID(ctx, clientID)
if err != nil {
return err
}
if app.OIDCConfig != nil {
return a.Commands.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret)
}
return a.Commands.VerifyAPIClientSecret(ctx, app.ProjectID, app.ID, secret)
}

View File

@ -24,7 +24,6 @@ import (
user_model "github.com/caos/zitadel/internal/user/model" user_model "github.com/caos/zitadel/internal/user/model"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
) )
type AuthRequestRepo struct { type AuthRequestRepo struct {
@ -104,7 +103,7 @@ type orgViewProvider interface {
type userGrantProvider interface { type userGrantProvider interface {
ProjectByOIDCClientID(context.Context, string) (*query.Project, error) ProjectByOIDCClientID(context.Context, string) (*query.Project, error)
UserGrantsByProjectAndUserID(string, string) ([]*grant_view_model.UserGrantView, error) UserGrantsByProjectAndUserID(string, string) ([]*query.UserGrant, error)
} }
type projectProvider interface { type projectProvider interface {

View File

@ -20,7 +20,6 @@ import (
user_model "github.com/caos/zitadel/internal/user/model" user_model "github.com/caos/zitadel/internal/user/model"
user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
) )
type mockViewNoUserSession struct{} type mockViewNoUserSession struct{}
@ -216,10 +215,10 @@ func (m *mockUserGrants) ProjectByOIDCClientID(ctx context.Context, s string) (*
return &query.Project{ProjectRoleCheck: m.roleCheck}, nil return &query.Project{ProjectRoleCheck: m.roleCheck}, nil
} }
func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*grant_view_model.UserGrantView, error) { func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*query.UserGrant, error) {
var grants []*grant_view_model.UserGrantView var grants []*query.UserGrant
if m.userGrants > 0 { if m.userGrants > 0 {
grants = make([]*grant_view_model.UserGrantView, m.userGrants) grants = make([]*query.UserGrant, m.userGrants)
} }
return grants, nil return grants, nil
} }

View File

@ -1,322 +0,0 @@
package eventstore
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
)
type UserGrantRepo struct {
SearchLimit uint64
View *view.View
IamID string
Auth authz.Config
AuthZRepo *authz_repo.EsRepository
PrefixAvatarURL string
Query *query.Queries
}
func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) {
err := request.EnsureLimit(repo.SearchLimit)
if err != nil {
return nil, err
}
sequence, err := repo.View.GetLatestUserGrantSequence()
logging.Log("EVENT-Hd7s3").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest user grant sequence")
request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.UserGrantSearchKeyUserID, Method: domain.SearchMethodEquals, Value: authz.GetCtxData(ctx).UserID})
grants, count, err := repo.View.SearchUserGrants(request)
if err != nil {
return nil, err
}
result := &grant_model.UserGrantSearchResponse{
Offset: request.Offset,
Limit: request.Limit,
TotalResult: count,
Result: model.UserGrantsToModel(grants, repo.PrefixAvatarURL),
}
if err == nil {
result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
func (repo *UserGrantRepo) SearchMyProjectOrgs(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) {
err := request.EnsureLimit(repo.SearchLimit)
if err != nil {
return nil, err
}
ctxData := authz.GetCtxData(ctx)
if ctxData.ProjectID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "APP-7lqva", "Could not get ProjectID")
}
err = repo.AuthZRepo.FillIamProjectID(ctx)
if err != nil {
return nil, err
}
if ctxData.ProjectID == repo.AuthZRepo.UserGrantRepo.IamProjectID {
isAdmin, err := repo.IsIamAdmin(ctx)
if err != nil {
return nil, err
}
if isAdmin {
return repo.SearchAdminOrgs(request)
}
return repo.searchZitadelOrgs(ctxData, request)
}
request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.UserGrantSearchKeyProjectID, Method: domain.SearchMethodEquals, Value: ctxData.ProjectID})
grants, err := repo.SearchMyUserGrants(ctx, request)
if err != nil {
return nil, err
}
if len(grants.Result) > 0 {
return grantRespToOrgResp(grants), nil
}
return repo.userOrg(ctxData)
}
func (repo *UserGrantRepo) membershipsToOrgResp(memberships *query.Memberships) *grant_model.ProjectOrgSearchResponse {
orgs := make([]*grant_model.Org, 0, len(memberships.Memberships))
for _, m := range memberships.Memberships {
if !containsOrg(orgs, m.ResourceOwner) {
org, err := repo.Query.OrgByID(context.TODO(), m.ResourceOwner)
if err != nil {
logging.LogWithFields("EVENT-k8Ikl", "owner", m.ResourceOwner).WithError(err).Warn("org not found")
orgs = append(orgs, &grant_model.Org{OrgID: m.ResourceOwner})
continue
}
orgs = append(orgs, &grant_model.Org{OrgID: m.ResourceOwner, OrgName: org.Name})
}
}
return &grant_model.ProjectOrgSearchResponse{
TotalResult: memberships.Count,
Result: orgs,
}
}
func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) {
memberships, err := repo.searchUserMemberships(ctx)
if err != nil {
return nil, err
}
permissions := &grant_model.Permissions{Permissions: []string{}}
for _, membership := range memberships {
for _, role := range membership.Roles {
permissions = repo.mapRoleToPermission(permissions, membership, role)
}
}
return permissions.Permissions, nil
}
func (repo *UserGrantRepo) searchUserMemberships(ctx context.Context) ([]*query.Membership, error) {
ctxData := authz.GetCtxData(ctx)
userQuery, err := query.NewMembershipUserIDQuery(ctxData.UserID)
if err != nil {
return nil, err
}
ownerQuery, err := query.NewMembershipResourceOwnerQuery(ctxData.OrgID)
if err != nil {
return nil, err
}
orgMemberships, err := repo.Query.Memberships(ctx, &query.MembershipSearchQuery{
Queries: []query.SearchQuery{userQuery, ownerQuery},
})
if err != nil {
return nil, err
}
iamQuery, err := query.NewMembershipIsIAMQuery()
if err != nil {
return nil, err
}
iamMemberships, err := repo.Query.Memberships(ctx, &query.MembershipSearchQuery{
Queries: []query.SearchQuery{userQuery, iamQuery},
})
if err != nil {
return nil, err
}
if orgMemberships.Count == 0 && iamMemberships.Count == 0 {
return []*query.Membership{}, nil
}
return append(orgMemberships.Memberships, iamMemberships.Memberships...), nil
}
func (repo *UserGrantRepo) SearchMyProjectPermissions(ctx context.Context) ([]string, error) {
ctxData := authz.GetCtxData(ctx)
//TODO: blocked until user grants moved to query-pkg
usergrant, err := repo.View.UserGrantByIDs(ctxData.OrgID, ctxData.ProjectID, ctxData.UserID)
if err != nil {
return nil, err
}
permissions := make([]string, len(usergrant.RoleKeys))
for i, role := range usergrant.RoleKeys {
permissions[i] = role
}
return permissions, nil
}
func (repo *UserGrantRepo) SearchAdminOrgs(request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) {
searchRequest := query.OrgSearchQueries{
SearchRequest: query.SearchRequest{
SortingColumn: query.OrgColumnName,
Asc: true,
},
}
if len(request.Queries) > 0 {
for _, q := range request.Queries {
if q.Key == grant_model.UserGrantSearchKeyOrgName {
nameQuery, err := query.NewOrgNameSearchQuery(query.TextComparisonFromMethod(q.Method), q.Value.(string))
if err != nil {
return nil, err
}
searchRequest.Queries = append(searchRequest.Queries, nameQuery)
}
}
}
orgs, err := repo.Query.SearchOrgs(context.TODO(), &searchRequest)
if err != nil {
return nil, err
}
return orgRespToOrgResp(orgs), nil
}
func (repo *UserGrantRepo) IsIamAdmin(ctx context.Context) (bool, error) {
//TODO: blocked until user grants moved to query
grantSearch := &grant_model.UserGrantSearchRequest{
Queries: []*grant_model.UserGrantSearchQuery{
{Key: grant_model.UserGrantSearchKeyResourceOwner, Method: domain.SearchMethodEquals, Value: repo.IamID},
}}
result, err := repo.SearchMyUserGrants(ctx, grantSearch)
if err != nil {
return false, err
}
if result.TotalResult == 0 {
return false, nil
}
return true, nil
}
func (repo *UserGrantRepo) UserGrantsByProjectAndUserID(projectID, userID string) ([]*grant_model.UserGrantView, error) {
grants, err := repo.View.UserGrantsByProjectAndUserID(projectID, userID)
if err != nil {
return nil, err
}
return model.UserGrantsToModel(grants, repo.PrefixAvatarURL), nil
}
func (repo *UserGrantRepo) userOrg(ctxData authz.CtxData) (*grant_model.ProjectOrgSearchResponse, error) {
//TODO: blocked until user moved to query pkg
user, err := repo.View.UserByID(ctxData.UserID)
if err != nil {
return nil, err
}
org, err := repo.Query.OrgByID(context.TODO(), user.ResourceOwner)
if err != nil {
return nil, err
}
return &grant_model.ProjectOrgSearchResponse{Result: []*grant_model.Org{{
OrgID: org.ID,
OrgName: org.Name,
}}}, nil
}
func (repo *UserGrantRepo) searchZitadelOrgs(ctxData authz.CtxData, request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) {
userQuery, err := query.NewMembershipUserIDQuery(ctxData.UserID)
if err != nil {
return nil, err
}
memberships, err := repo.Query.Memberships(context.TODO(), &query.MembershipSearchQuery{
SearchRequest: query.SearchRequest{
Offset: request.Offset,
Limit: request.Limit,
Asc: request.Asc,
//TODO: sorting column
},
Queries: []query.SearchQuery{userQuery},
})
if err != nil {
return nil, err
}
if len(memberships.Memberships) > 0 {
return repo.membershipsToOrgResp(memberships), nil
}
return repo.userOrg(ctxData)
}
func (repo *UserGrantRepo) mapRoleToPermission(permissions *grant_model.Permissions, membership *query.Membership, role string) *grant_model.Permissions {
for _, mapping := range repo.Auth.RolePermissionMappings {
if mapping.Role == role {
ctxID := ""
if membership.Project != nil {
ctxID = membership.Project.ProjectID
} else if membership.ProjectGrant != nil {
ctxID = membership.ProjectGrant.GrantID
}
permissions.AppendPermissions(ctxID, mapping.Permissions...)
}
}
return permissions
}
func grantRespToOrgResp(grants *grant_model.UserGrantSearchResponse) *grant_model.ProjectOrgSearchResponse {
resp := &grant_model.ProjectOrgSearchResponse{
TotalResult: grants.TotalResult,
}
resp.Result = make([]*grant_model.Org, len(grants.Result))
for i, g := range grants.Result {
resp.Result[i] = &grant_model.Org{OrgID: g.ResourceOwner, OrgName: g.OrgName}
}
return resp
}
func orgRespToOrgResp(orgs *query.Orgs) *grant_model.ProjectOrgSearchResponse {
resp := &grant_model.ProjectOrgSearchResponse{
TotalResult: orgs.Count,
}
resp.Result = make([]*grant_model.Org, len(orgs.Orgs))
for i, o := range orgs.Orgs {
resp.Result[i] = &grant_model.Org{OrgID: o.ID, OrgName: o.Name}
}
return resp
}
func containsOrg(orgs []*grant_model.Org, resourceOwner string) bool {
for _, org := range orgs {
if org.OrgID == resourceOwner {
return true
}
}
return false
}
func userMembershipToMembership(membership *user_view_model.UserMembershipView) *authz.Membership {
return &authz.Membership{
MemberType: authz.MemberType(membership.MemberType),
AggregateID: membership.AggregateID,
ObjectID: membership.ObjectID,
Roles: membership.Roles,
}
}
func userMembershipsToMemberships(memberships []*user_view_model.UserMembershipView) []*authz.Membership {
result := make([]*authz.Membership, len(memberships))
for i, m := range memberships {
result[i] = userMembershipToMembership(m)
}
return result
}

View File

@ -39,9 +39,6 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount, es}), handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount, es}),
newToken( newToken(
handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount, es}), handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount, es}),
newUserGrant(
handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es},
systemDefaults.IamID),
newIDPConfig( newIDPConfig(
handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}), handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}),
newIDPProvider( newIDPProvider(

View File

@ -1,541 +0,0 @@
package handler
import (
"context"
"strings"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
org_model "github.com/caos/zitadel/internal/org/model"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
proj_model "github.com/caos/zitadel/internal/project/model"
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
proj_view "github.com/caos/zitadel/internal/project/repository/view"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
)
const (
userGrantTable = "auth.user_grants"
)
type UserGrant struct {
handler
iamID string
iamProjectID string
subscription *v1.Subscription
}
func newUserGrant(
handler handler,
iamID string,
) *UserGrant {
h := &UserGrant{
handler: handler,
iamID: iamID,
}
h.subscribe()
return h
}
func (k *UserGrant) subscribe() {
k.subscription = k.es.Subscribe(k.AggregateTypes()...)
go func() {
for event := range k.subscription.Events {
query.ReduceEvent(k, event)
}
}()
}
func (u *UserGrant) ViewModel() string {
return userGrantTable
}
func (u *UserGrant) Subscription() *v1.Subscription {
return u.subscription
}
func (_ *UserGrant) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{grant_es_model.UserGrantAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate}
}
func (u *UserGrant) CurrentSequence() (uint64, error) {
sequence, err := u.view.GetLatestUserGrantSequence()
if err != nil {
return 0, err
}
return sequence.CurrentSequence, nil
}
func (u *UserGrant) EventQuery() (*es_models.SearchQuery, error) {
if u.iamProjectID == "" {
err := u.setIamProjectID()
if err != nil {
return nil, err
}
}
sequence, err := u.view.GetLatestUserGrantSequence()
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
AggregateTypeFilter(u.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
func (u *UserGrant) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case grant_es_model.UserGrantAggregate:
err = u.processUserGrant(event)
case usr_es_model.UserAggregate:
err = u.processUser(event)
case proj_es_model.ProjectAggregate:
err = u.processProject(event)
case iam_es_model.IAMAggregate:
err = u.processIAMMember(event, "IAM", false)
case org_es_model.OrgAggregate:
return u.processOrg(event)
}
return err
}
func (u *UserGrant) processUserGrant(event *es_models.Event) (err error) {
grant := new(view_model.UserGrantView)
switch event.Type {
case grant_es_model.UserGrantAdded:
err = grant.AppendEvent(event)
if err != nil {
return err
}
err = u.fillData(grant, event.ResourceOwner)
case grant_es_model.UserGrantChanged,
grant_es_model.UserGrantCascadeChanged,
grant_es_model.UserGrantDeactivated,
grant_es_model.UserGrantReactivated:
grant, err = u.view.UserGrantByID(event.AggregateID)
if err != nil {
return err
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
return u.view.DeleteUserGrant(event.AggregateID, event)
default:
return u.view.ProcessedUserGrantSequence(event)
}
if err != nil {
return err
}
return u.view.PutUserGrant(grant, event)
}
func (u *UserGrant) processUser(event *es_models.Event) (err error) {
switch event.Type {
case usr_es_model.UserProfileChanged,
usr_es_model.UserEmailChanged,
usr_es_model.HumanProfileChanged,
usr_es_model.HumanEmailChanged,
usr_es_model.MachineChanged,
usr_es_model.HumanAvatarAdded,
usr_es_model.HumanAvatarRemoved:
grants, err := u.view.UserGrantsByUserID(event.AggregateID)
if err != nil {
return err
}
if len(grants) == 0 {
return u.view.ProcessedUserGrantSequence(event)
}
user, err := u.getUserByID(event.AggregateID)
if err != nil {
return err
}
for _, grant := range grants {
u.fillUserData(grant, user)
}
return u.view.PutUserGrants(grants, event)
default:
return u.view.ProcessedUserGrantSequence(event)
}
}
func (u *UserGrant) processProject(event *es_models.Event) (err error) {
switch event.Type {
case proj_es_model.ProjectChanged:
proj := new(proj_es_model.Project)
err := proj.SetData(event)
if err != nil {
return err
}
if proj.Name == "" {
return u.view.ProcessedUserGrantSequence(event)
}
grants, err := u.view.UserGrantsByProjectID(event.AggregateID)
if err != nil {
return err
}
for _, grant := range grants {
grant.ProjectName = proj.Name
}
return u.view.PutUserGrants(grants, event)
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged,
proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberCascadeRemoved:
member := new(proj_es_model.ProjectMember)
err := member.SetData(event)
if err != nil {
return err
}
return u.processMember(event, "PROJECT", event.AggregateID, member.UserID, member.Roles)
case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged,
proj_es_model.ProjectGrantMemberRemoved, proj_es_model.ProjectGrantMemberCascadeRemoved:
member := new(proj_es_model.ProjectGrantMember)
err := member.SetData(event)
if err != nil {
return err
}
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
default:
return u.view.ProcessedUserGrantSequence(event)
}
}
func (u *UserGrant) processOrg(event *es_models.Event) (err error) {
switch event.Type {
case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged,
org_es_model.OrgMemberRemoved, org_es_model.OrgMemberCascadeRemoved:
member := new(org_es_model.OrgMember)
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
case org_es_model.OrgChanged:
grants, err := u.view.UserGrantsByProjectID(event.AggregateID)
if err != nil {
return err
}
if len(grants) == 0 {
return u.view.ProcessedUserGrantSequence(event)
}
org, err := u.getOrgByID(context.Background(), event.AggregateID)
if err != nil {
return err
}
for _, grant := range grants {
u.fillOrgData(grant, org)
}
return u.view.PutUserGrants(grants, event)
default:
return u.view.ProcessedUserGrantSequence(event)
}
}
func (u *UserGrant) processIAMMember(event *es_models.Event, rolePrefix string, suffix bool) error {
member := new(iam_es_model.IAMMember)
switch event.Type {
case iam_es_model.IAMMemberAdded, iam_es_model.IAMMemberChanged:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil && !errors.IsNotFound(err) {
return err
}
if errors.IsNotFound(err) {
grant = &view_model.UserGrantView{
ID: u.iamProjectID + member.UserID,
ResourceOwner: u.iamID,
OrgName: u.iamID,
ProjectID: u.iamProjectID,
UserID: member.UserID,
RoleKeys: member.Roles,
CreationDate: event.CreationDate,
}
if suffix {
grant.RoleKeys = suffixRoles(event.AggregateID, grant.RoleKeys)
}
} else {
newRoles := member.Roles
if grant.RoleKeys != nil {
grant.RoleKeys = mergeExistingRoles(rolePrefix, "", grant.RoleKeys, newRoles)
} else {
grant.RoleKeys = newRoles
}
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event)
case iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
return err
}
return u.view.DeleteUserGrant(grant.ID, event)
default:
return u.view.ProcessedUserGrantSequence(event)
}
}
func (u *UserGrant) processMember(event *es_models.Event, rolePrefix, roleSuffix string, userID string, roleKeys []string) error {
switch event.Type {
case org_es_model.OrgMemberAdded, proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded,
org_es_model.OrgMemberChanged, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectGrantMemberChanged:
grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID)
if err != nil && !errors.IsNotFound(err) {
return err
}
if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys)
}
if errors.IsNotFound(err) {
grant = &view_model.UserGrantView{
ID: u.iamProjectID + event.ResourceOwner + userID,
ResourceOwner: event.ResourceOwner,
ProjectID: u.iamProjectID,
UserID: userID,
RoleKeys: roleKeys,
CreationDate: event.CreationDate,
}
u.fillData(grant, event.ResourceOwner)
} else {
newRoles := roleKeys
if grant.RoleKeys != nil {
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, newRoles)
} else {
grant.RoleKeys = newRoles
}
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event)
case org_es_model.OrgMemberRemoved,
org_es_model.OrgMemberCascadeRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectMemberCascadeRemoved,
proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID)
if err != nil && !errors.IsNotFound(err) {
return err
}
if errors.IsNotFound(err) {
return u.view.ProcessedUserGrantSequence(event)
}
if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys)
}
if grant.RoleKeys == nil {
return u.view.ProcessedUserGrantSequence(event)
}
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil)
return u.view.PutUserGrant(grant, event)
default:
return u.view.ProcessedUserGrantSequence(event)
}
}
func suffixRoles(suffix string, roles []string) []string {
suffixedRoles := make([]string, len(roles))
for i := 0; i < len(roles); i++ {
suffixedRoles[i] = roles[i] + ":" + suffix
}
return suffixedRoles
}
func mergeExistingRoles(rolePrefix, suffix string, existingRoles, newRoles []string) []string {
mergedRoles := make([]string, 0)
for _, existingRole := range existingRoles {
if !strings.HasPrefix(existingRole, rolePrefix) {
mergedRoles = append(mergedRoles, existingRole)
continue
}
if suffix != "" && !strings.HasSuffix(existingRole, suffix) {
mergedRoles = append(mergedRoles, existingRole)
}
}
return append(mergedRoles, newRoles...)
}
func (u *UserGrant) setIamProjectID() error {
if u.iamProjectID != "" {
return nil
}
iam, err := u.getIAMByID(context.Background())
if err != nil {
return err
}
if iam.SetUpDone < domain.StepCount-1 {
return errors.ThrowPreconditionFailed(nil, "HANDL-s5DTs", "Setup not done")
}
u.iamProjectID = iam.IAMProjectID
return nil
}
func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) {
user, err := u.getUserByID(grant.UserID)
if err != nil {
return err
}
u.fillUserData(grant, user)
project, err := u.getProjectByID(context.Background(), grant.ProjectID)
if err != nil {
return err
}
u.fillProjectData(grant, project)
org, err := u.getOrgByID(context.TODO(), resourceOwner)
if err != nil {
return err
}
u.fillOrgData(grant, org)
return nil
}
func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *model.UserView) {
grant.UserName = user.UserName
grant.UserResourceOwner = user.ResourceOwner
if user.HumanView != nil {
grant.FirstName = user.FirstName
grant.LastName = user.LastName
grant.DisplayName = user.FirstName + " " + user.LastName
grant.Email = user.Email
grant.AvatarKey = user.AvatarKey
}
if user.MachineView != nil {
grant.DisplayName = user.MachineView.Name
}
}
func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *proj_model.Project) {
grant.ProjectName = project.Name
grant.ProjectOwner = project.ResourceOwner
}
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
grant.OrgName = org.Name
for _, domain := range org.Domains {
if domain.Primary {
grant.OrgPrimaryDomain = domain.Domain
break
}
}
}
func (u *UserGrant) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-UZmc7", "id", event.AggregateID).WithError(err).Warn("something went wrong in user grant handler")
return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip)
}
func (u *UserGrant) OnSuccess() error {
return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp)
}
func (u *UserGrant) getUserByID(userID string) (*model.UserView, error) {
user, usrErr := u.view.UserByID(userID)
if usrErr != nil && !errors.IsNotFound(usrErr) {
return nil, usrErr
}
if user == nil {
user = &model.UserView{}
}
events, err := u.getUserEvents(userID, user.Sequence)
if err != nil {
return user, usrErr
}
userCopy := *user
for _, event := range events {
if err := userCopy.AppendEvent(event); err != nil {
return user, nil
}
}
if userCopy.State == int32(usr_model.UserStateDeleted) {
return nil, errors.ThrowNotFound(nil, "HANDLER-m9dos", "Errors.User.NotFound")
}
return &userCopy, nil
}
func (u *UserGrant) getUserEvents(userID string, sequence uint64) ([]*es_models.Event, error) {
query, err := view.UserByIDQuery(userID, sequence)
if err != nil {
return nil, err
}
return u.es.FilterEvents(context.Background(), query)
}
func (u *UserGrant) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) {
query, err := org_view.OrgByIDQuery(orgID, 0)
if err != nil {
return nil, err
}
esOrg := &org_es_model.Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: orgID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query)
if err != nil && !errors.IsNotFound(err) {
return nil, err
}
if esOrg.Sequence == 0 {
return nil, errors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound")
}
return org_es_model.OrgToModel(esOrg), nil
}
func (u *UserGrant) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) {
query, err := proj_view.ProjectByIDQuery(projID, 0)
if err != nil {
return nil, err
}
esProject := &proj_es_model.Project{
ObjectRoot: es_models.ObjectRoot{
AggregateID: projID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query)
if err != nil && !errors.IsNotFound(err) {
return nil, err
}
if esProject.Sequence == 0 {
return nil, errors.ThrowNotFound(nil, "EVENT-DAfng", "Errors.Project.NotFound")
}
return proj_es_model.ProjectToModel(esProject), nil
}
func (u *UserGrant) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: es_models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query)
if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}

View File

@ -3,17 +3,14 @@ package eventsourcing
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/eventstore" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/spooler" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/spooler"
auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/auth_request/repository/cache" "github.com/caos/zitadel/internal/auth_request/repository/cache"
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
"github.com/caos/zitadel/internal/command" "github.com/caos/zitadel/internal/command"
sd "github.com/caos/zitadel/internal/config/systemdefaults" sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
es2 "github.com/caos/zitadel/internal/eventstore"
v1 "github.com/caos/zitadel/internal/eventstore/v1" v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_spol "github.com/caos/zitadel/internal/eventstore/v1/spooler" es_spol "github.com/caos/zitadel/internal/eventstore/v1/spooler"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
@ -37,13 +34,11 @@ type EsRepository struct {
eventstore.AuthRequestRepo eventstore.AuthRequestRepo
eventstore.TokenRepo eventstore.TokenRepo
eventstore.RefreshTokenRepo eventstore.RefreshTokenRepo
eventstore.ApplicationRepo
eventstore.UserSessionRepo eventstore.UserSessionRepo
eventstore.UserGrantRepo
eventstore.OrgRepository eventstore.OrgRepository
} }
func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, authZRepo *authz_repo.EsRepository, esV2 *es2.Eventstore) (*EsRepository, error) { func Start(conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries) (*EsRepository, error) {
es, err := v1.Start(conf.Eventstore) es, err := v1.Start(conf.Eventstore)
if err != nil { if err != nil {
return nil, err return nil, err
@ -83,10 +78,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
PrefixAvatarURL: assetsAPI, PrefixAvatarURL: assetsAPI,
} }
//TODO: remove as soon as possible //TODO: remove as soon as possible
queryView := struct { queryView := queryViewWrapper{
*query.Queries
*auth_view.View
}{
queries, queries,
view, view,
} }
@ -131,22 +123,9 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
SearchLimit: conf.SearchLimit, SearchLimit: conf.SearchLimit,
KeyAlgorithm: keyAlgorithm, KeyAlgorithm: keyAlgorithm,
}, },
eventstore.ApplicationRepo{
Commands: command,
Query: queries,
},
eventstore.UserSessionRepo{ eventstore.UserSessionRepo{
View: view, View: view,
}, },
eventstore.UserGrantRepo{
SearchLimit: conf.SearchLimit,
View: view,
IamID: systemDefaults.IamID,
Auth: authZ,
AuthZRepo: authZRepo,
Query: queries,
},
eventstore.OrgRepository{ eventstore.OrgRepository{
SearchLimit: conf.SearchLimit, SearchLimit: conf.SearchLimit,
View: view, View: view,
@ -157,6 +136,27 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
}, nil }, nil
} }
type queryViewWrapper struct {
*query.Queries
*auth_view.View
}
func (q queryViewWrapper) UserGrantsByProjectAndUserID(projectID, userID string) ([]*query.UserGrant, error) {
userGrantProjectID, err := query.NewUserGrantProjectIDSearchQuery(projectID)
if err != nil {
return nil, err
}
userGrantUserID, err := query.NewUserGrantUserIDSearchQuery(userID)
if err != nil {
return nil, err
}
queries := &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantUserID, userGrantProjectID}}
grants, err := q.Queries.UserGrants(context.TODO(), queries)
if err != nil {
return nil, err
}
return grants.UserGrants, nil
}
func (repo *EsRepository) Health(ctx context.Context) error { func (repo *EsRepository) Health(ctx context.Context) error {
if err := repo.UserRepo.Health(ctx); err != nil { if err := repo.UserRepo.Health(ctx); err != nil {
return err return err

View File

@ -1,89 +0,0 @@
package view
import (
"time"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/key/repository/view"
"github.com/caos/zitadel/internal/key/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
const (
keyTable = "auth.keys"
)
func (v *View) KeyByIDAndType(keyID string, private bool) (*model.KeyView, error) {
return view.KeyByIDAndType(v.Db, keyTable, keyID, private)
}
func (v *View) GetActivePrivateKeyForSigning(expiry time.Time) (*key_model.KeyView, error) {
key, err := view.GetSigningKey(v.Db, keyTable, expiry)
if err != nil {
return nil, err
}
return model.KeyViewToModel(key), nil
}
func (v *View) GetSigningKey(expiry time.Time) (*key_model.SigningKey, time.Time, error) {
key, err := view.GetSigningKey(v.Db, keyTable, expiry)
if err != nil {
return nil, time.Time{}, err
}
signingKey, err := key_model.SigningKeyFromKeyView(model.KeyViewToModel(key), v.keyAlgorithm)
return signingKey, key.Expiry, err
}
func (v *View) GetActiveKeySet() ([]*key_model.PublicKey, error) {
keys, err := view.GetActivePublicKeys(v.Db, keyTable)
if err != nil {
return nil, err
}
return key_model.PublicKeysFromKeyView(model.KeyViewsToModel(keys), v.keyAlgorithm)
}
func (v *View) PutKeys(privateKey, publicKey *model.KeyView, event *models.Event) error {
err := view.PutKeys(v.Db, keyTable, privateKey, publicKey)
if err != nil {
return err
}
return v.ProcessedKeySequence(event)
}
func (v *View) DeleteKey(keyID string, private bool, event *models.Event) error {
err := view.DeleteKey(v.Db, keyTable, keyID, private)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedKeySequence(event)
}
func (v *View) DeleteKeyPair(keyID string, event *models.Event) error {
err := view.DeleteKeyPair(v.Db, keyTable, keyID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedKeySequence(event)
}
func (v *View) GetLatestKeySequence() (*repository.CurrentSequence, error) {
return v.latestSequence(keyTable)
}
func (v *View) ProcessedKeySequence(event *models.Event) error {
return v.saveCurrentSequence(keyTable, event)
}
func (v *View) UpdateKeySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(keyTable)
}
func (v *View) GetLatestKeyFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
return v.latestFailedEvent(keyTable, sequence)
}
func (v *View) ProcessedKeyFailedEvent(failedEvent *repository.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@ -1,86 +0,0 @@
package view
import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
const (
userGrantTable = "auth.user_grants"
)
func (v *View) UserGrantByID(grantID string) (*model.UserGrantView, error) {
return view.UserGrantByID(v.Db, userGrantTable, grantID)
}
func (v *View) UserGrantByIDs(resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) {
return view.UserGrantByIDs(v.Db, userGrantTable, resourceOwnerID, projectID, userID)
}
func (v *View) UserGrantsByUserID(userID string) ([]*model.UserGrantView, error) {
return view.UserGrantsByUserID(v.Db, userGrantTable, userID)
}
func (v *View) UserGrantsByProjectID(projectID string) ([]*model.UserGrantView, error) {
return view.UserGrantsByProjectID(v.Db, userGrantTable, projectID)
}
func (v *View) UserGrantsByOrgID(projectID string) ([]*model.UserGrantView, error) {
return view.UserGrantsByOrgID(v.Db, userGrantTable, projectID)
}
func (v *View) UserGrantsByProjectAndUserID(projectID, userID string) ([]*model.UserGrantView, error) {
return view.UserGrantsByProjectAndUserID(v.Db, userGrantTable, projectID, userID)
}
func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, uint64, error) {
return view.SearchUserGrants(v.Db, userGrantTable, request)
}
func (v *View) PutUserGrant(grant *model.UserGrantView, event *models.Event) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
return v.ProcessedUserGrantSequence(event)
}
func (v *View) PutUserGrants(grants []*model.UserGrantView, event *models.Event) error {
err := view.PutUserGrants(v.Db, userGrantTable, grants...)
if err != nil {
return err
}
return v.ProcessedUserGrantSequence(event)
}
func (v *View) DeleteUserGrant(grantID string, event *models.Event) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedUserGrantSequence(event)
}
func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userGrantTable)
}
func (v *View) ProcessedUserGrantSequence(event *models.Event) error {
return v.saveCurrentSequence(userGrantTable, event)
}
func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(userGrantTable)
}
func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
return v.latestFailedEvent(userGrantTable, sequence)
}
func (v *View) ProcessedUserGrantFailedEvent(failedEvent *repository.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@ -9,9 +9,7 @@ type Repository interface {
UserRepository UserRepository
AuthRequestRepository AuthRequestRepository
TokenRepository TokenRepository
ApplicationRepository
UserSessionRepository UserSessionRepository
UserGrantRepository
OrgRepository OrgRepository
RefreshTokenRepository RefreshTokenRepository
} }

View File

@ -1,14 +0,0 @@
package repository
import (
"context"
"github.com/caos/zitadel/internal/usergrant/model"
)
type UserGrantRepository interface {
SearchMyUserGrants(ctx context.Context, request *model.UserGrantSearchRequest) (*model.UserGrantSearchResponse, error)
SearchMyProjectOrgs(ctx context.Context, request *model.UserGrantSearchRequest) (*model.ProjectOrgSearchResponse, error)
SearchMyZitadelPermissions(ctx context.Context) ([]string, error)
SearchMyProjectPermissions(ctx context.Context) ([]string, error)
UserGrantsByProjectAndUserID(projectID, userID string) ([]*model.UserGrantView, error)
}

View File

@ -1,9 +1,7 @@
package authz package authz
import ( import (
"context" "github.com/caos/zitadel/internal/authz/repository"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
sd "github.com/caos/zitadel/internal/config/systemdefaults" sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
@ -13,6 +11,6 @@ type Config struct {
Repository eventsourcing.Config Repository eventsourcing.Config
} }
func Start(ctx context.Context, config Config, authZ authz.Config, systemDefaults sd.SystemDefaults, queries *query.Queries) (*eventsourcing.EsRepository, error) { func Start(config Config, systemDefaults sd.SystemDefaults, queries *query.Queries) (repository.Repository, error) {
return eventsourcing.Start(config.Repository, authZ, systemDefaults, queries) return eventsourcing.Start(config.Repository, systemDefaults, queries)
} }

View File

@ -14,9 +14,6 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
v1 "github.com/caos/zitadel/internal/eventstore/v1" v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/eventstore/v1/models" "github.com/caos/zitadel/internal/eventstore/v1/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view" iam_view "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/query" "github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
@ -33,7 +30,7 @@ type TokenVerifierRepo struct {
Query *query.Queries Query *query.Queries
} }
func (repo *TokenVerifierRepo) TokenByID(ctx context.Context, tokenID, userID string) (*usr_model.TokenView, error) { func (repo *TokenVerifierRepo) tokenByID(ctx context.Context, tokenID, userID string) (*usr_model.TokenView, error) {
token, viewErr := repo.View.TokenByID(tokenID) token, viewErr := repo.View.TokenByID(tokenID)
if viewErr != nil && !caos_errs.IsNotFound(viewErr) { if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr return nil, viewErr
@ -82,7 +79,7 @@ func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenStrin
if len(splittedToken) != 2 { if len(splittedToken) != 2 {
return "", "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-GDg3a", "invalid token") return "", "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-GDg3a", "invalid token")
} }
token, err := repo.TokenByID(ctx, splittedToken[0], splittedToken[1]) token, err := repo.tokenByID(ctx, splittedToken[0], splittedToken[1])
if err != nil { if err != nil {
return "", "", "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token") return "", "", "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token")
} }
@ -237,7 +234,7 @@ func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName str
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
iam, err := repo.getIAMByID(ctx) iam, err := repo.Query.IAMByID(ctx, domain.IAMID)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
@ -261,23 +258,6 @@ func (r *TokenVerifierRepo) getUserEvents(ctx context.Context, userID string, se
return r.Eventstore.FilterEvents(ctx, query) return r.Eventstore.FilterEvents(ctx, query)
} }
func (u *TokenVerifierRepo) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore.FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}
func (repo *TokenVerifierRepo) checkDefaultFeatures(ctx context.Context, requiredFeatures ...string) error { func (repo *TokenVerifierRepo) checkDefaultFeatures(ctx context.Context, requiredFeatures ...string) error {
features, err := repo.Query.DefaultFeatures(ctx) features, err := repo.Query.DefaultFeatures(ctx)
if err != nil { if err != nil {

View File

@ -1,158 +0,0 @@
package eventstore
import (
"context"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/eventstore/v1/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
user_model "github.com/caos/zitadel/internal/user/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
)
type UserGrantRepo struct {
View *view.View
IamID string
IamProjectID string
Auth authz.Config
Eventstore v1.Eventstore
}
func (repo *UserGrantRepo) Health() error {
return repo.View.Health()
}
func (repo *UserGrantRepo) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) {
memberships, err := repo.searchUserMemberships(ctx)
if err != nil {
return nil, err
}
return userMembershipsToMemberships(memberships), nil
}
func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) {
memberships, err := repo.searchUserMemberships(ctx)
if err != nil {
return nil, err
}
permissions := &grant_model.Permissions{Permissions: []string{}}
for _, membership := range memberships {
for _, role := range membership.Roles {
permissions = repo.mapRoleToPermission(permissions, membership, role)
}
}
return permissions.Permissions, nil
}
func (repo *UserGrantRepo) searchUserMemberships(ctx context.Context) ([]*user_view_model.UserMembershipView, error) {
ctxData := authz.GetCtxData(ctx)
orgMemberships, orgCount, err := repo.View.SearchUserMemberships(&user_model.UserMembershipSearchRequest{
Queries: []*user_model.UserMembershipSearchQuery{
{
Key: user_model.UserMembershipSearchKeyUserID,
Method: domain.SearchMethodEquals,
Value: ctxData.UserID,
},
{
Key: user_model.UserMembershipSearchKeyResourceOwner,
Method: domain.SearchMethodEquals,
Value: ctxData.OrgID,
},
},
})
if err != nil {
return nil, err
}
iamMemberships, iamCount, err := repo.View.SearchUserMemberships(&user_model.UserMembershipSearchRequest{
Queries: []*user_model.UserMembershipSearchQuery{
{
Key: user_model.UserMembershipSearchKeyUserID,
Method: domain.SearchMethodEquals,
Value: ctxData.UserID,
},
{
Key: user_model.UserMembershipSearchKeyAggregateID,
Method: domain.SearchMethodEquals,
Value: repo.IamID,
},
},
})
if err != nil {
return nil, err
}
if orgCount == 0 && iamCount == 0 {
return []*user_view_model.UserMembershipView{}, nil
}
return append(orgMemberships, iamMemberships...), nil
}
func (repo *UserGrantRepo) FillIamProjectID(ctx context.Context) error {
if repo.IamProjectID != "" {
return nil
}
iam, err := repo.getIAMByID(ctx)
if err != nil {
return err
}
if iam.SetUpDone < domain.StepCount-1 {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-skiwS", "Setup not done")
}
repo.IamProjectID = iam.IAMProjectID
return nil
}
func (repo *UserGrantRepo) mapRoleToPermission(permissions *grant_model.Permissions, membership *user_view_model.UserMembershipView, role string) *grant_model.Permissions {
for _, mapping := range repo.Auth.RolePermissionMappings {
if mapping.Role == role {
ctxID := ""
if membership.MemberType == int32(user_model.MemberTypeProject) || membership.MemberType == int32(user_model.MemberTypeProjectGrant) {
ctxID = membership.ObjectID
}
permissions.AppendPermissions(ctxID, mapping.Permissions...)
}
}
return permissions
}
func (u *UserGrantRepo) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore.FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}
func userMembershipToMembership(membership *user_view_model.UserMembershipView) *authz.Membership {
return &authz.Membership{
MemberType: authz.MemberType(membership.MemberType),
AggregateID: membership.AggregateID,
ObjectID: membership.ObjectID,
Roles: membership.Roles,
}
}
func userMembershipsToMemberships(memberships []*user_view_model.UserMembershipView) []*authz.Membership {
result := make([]*authz.Membership, len(memberships))
for i, m := range memberships {
result[i] = userMembershipToMembership(m)
}
return result
}

View File

@ -0,0 +1,86 @@
package eventstore
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/domain"
user_model "github.com/caos/zitadel/internal/user/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
type UserMembershipRepo struct {
View *view.View
}
func (repo *UserMembershipRepo) Health() error {
return repo.View.Health()
}
func (repo *UserMembershipRepo) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) {
memberships, err := repo.searchUserMemberships(ctx)
if err != nil {
return nil, err
}
return userMembershipsToMemberships(memberships), nil
}
func (repo *UserMembershipRepo) searchUserMemberships(ctx context.Context) ([]*user_view_model.UserMembershipView, error) {
ctxData := authz.GetCtxData(ctx)
orgMemberships, orgCount, err := repo.View.SearchUserMemberships(&user_model.UserMembershipSearchRequest{
Queries: []*user_model.UserMembershipSearchQuery{
{
Key: user_model.UserMembershipSearchKeyUserID,
Method: domain.SearchMethodEquals,
Value: ctxData.UserID,
},
{
Key: user_model.UserMembershipSearchKeyResourceOwner,
Method: domain.SearchMethodEquals,
Value: ctxData.OrgID,
},
},
})
if err != nil {
return nil, err
}
iamMemberships, iamCount, err := repo.View.SearchUserMemberships(&user_model.UserMembershipSearchRequest{
Queries: []*user_model.UserMembershipSearchQuery{
{
Key: user_model.UserMembershipSearchKeyUserID,
Method: domain.SearchMethodEquals,
Value: ctxData.UserID,
},
{
Key: user_model.UserMembershipSearchKeyAggregateID,
Method: domain.SearchMethodEquals,
Value: domain.IAMID,
},
},
})
if err != nil {
return nil, err
}
if orgCount == 0 && iamCount == 0 {
return []*user_view_model.UserMembershipView{}, nil
}
return append(orgMemberships, iamMemberships...), nil
}
func userMembershipToMembership(membership *user_view_model.UserMembershipView) *authz.Membership {
return &authz.Membership{
MemberType: authz.MemberType(membership.MemberType),
AggregateID: membership.AggregateID,
ObjectID: membership.ObjectID,
Roles: membership.Roles,
}
}
func userMembershipsToMemberships(memberships []*user_view_model.UserMembershipView) []*authz.Membership {
result := make([]*authz.Membership, len(memberships))
for i, m := range memberships {
result[i] = userMembershipToMembership(m)
}
return result
}

View File

@ -3,19 +3,17 @@ package eventsourcing
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/authz/repository"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/eventstore" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/spooler" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/spooler"
authz_view "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" authz_view "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
sd "github.com/caos/zitadel/internal/config/systemdefaults" sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/crypto"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_spol "github.com/caos/zitadel/internal/eventstore/v1/spooler" es_spol "github.com/caos/zitadel/internal/eventstore/v1/spooler"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
"github.com/caos/zitadel/internal/query"
) )
type Config struct { type Config struct {
@ -26,11 +24,11 @@ type Config struct {
type EsRepository struct { type EsRepository struct {
spooler *es_spol.Spooler spooler *es_spol.Spooler
eventstore.UserGrantRepo eventstore.UserMembershipRepo
eventstore.TokenVerifierRepo eventstore.TokenVerifierRepo
} }
func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, queries *query.Queries) (*EsRepository, error) { func Start(conf Config, systemDefaults sd.SystemDefaults, queries *query.Queries) (repository.Repository, error) {
es, err := v1.Start(conf.Eventstore) es, err := v1.Start(conf.Eventstore)
if err != nil { if err != nil {
return nil, err return nil, err
@ -56,16 +54,12 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, qu
return &EsRepository{ return &EsRepository{
spool, spool,
eventstore.UserGrantRepo{ eventstore.UserMembershipRepo{
View: view, View: view,
IamID: systemDefaults.IamID,
Auth: authZ,
Eventstore: es,
}, },
eventstore.TokenVerifierRepo{ eventstore.TokenVerifierRepo{
TokenVerificationKey: keyAlgorithm, TokenVerificationKey: keyAlgorithm,
Eventstore: es, Eventstore: es,
IAMID: systemDefaults.IamID,
View: view, View: view,
Query: queries, Query: queries,
}, },
@ -73,7 +67,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, qu
} }
func (repo *EsRepository) Health(ctx context.Context) error { func (repo *EsRepository) Health(ctx context.Context) error {
if err := repo.UserGrantRepo.Health(); err != nil { if err := repo.UserMembershipRepo.Health(); err != nil {
return err return err
} }
return nil return nil

View File

@ -1,10 +1,9 @@
package repository package repository
import ( import "context"
"context"
)
type Repository interface { type Repository interface {
Health(context.Context) error Health(context.Context) error
UserGrantRepository UserMembershipRepository
TokenVerifierRepository
} }

View File

@ -5,7 +5,8 @@ import (
) )
type TokenVerifierRepository interface { type TokenVerifierRepository interface {
VerifyAccessToken(ctx context.Context, appName string) (string, string, string, error) VerifyAccessToken(ctx context.Context, tokenString, verifierClientID, projectID string) (userID string, agentID string, clientID, prefLang, resourceOwner string, err error)
ProjectIDByClientID(ctx context.Context, clientID string) (string, error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
ExistsOrg(ctx context.Context, orgID string) error CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error
VerifierClientID(ctx context.Context, appName string) (clientID, projectID string, err error)
} }

View File

@ -1,12 +0,0 @@
package repository
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
)
type UserGrantRepository interface {
ResolveGrants(ctx context.Context) (*authz.Grant, error)
SearchMyZitadelPermissions(ctx context.Context) ([]string, error)
}

View File

@ -0,0 +1,11 @@
package repository
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
)
type UserMembershipRepository interface {
SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error)
}

View File

@ -5,16 +5,15 @@ import (
"time" "time"
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/api/http"
authz_repo "github.com/caos/zitadel/internal/authz/repository"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/action"
"github.com/caos/zitadel/internal/api/http"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
"github.com/caos/zitadel/internal/repository/action"
iam_repo "github.com/caos/zitadel/internal/repository/iam" iam_repo "github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/keypair" "github.com/caos/zitadel/internal/repository/keypair"
"github.com/caos/zitadel/internal/repository/org" "github.com/caos/zitadel/internal/repository/org"
@ -71,7 +70,7 @@ func StartCommands(
defaults sd.SystemDefaults, defaults sd.SystemDefaults,
authZConfig authz.Config, authZConfig authz.Config,
staticStore static.Storage, staticStore static.Storage,
authZRepo *authz_repo.EsRepository, authZRepo authz_repo.Repository,
) (repo *Commands, err error) { ) (repo *Commands, err error) {
repo = &Commands{ repo = &Commands{
eventstore: es, eventstore: es,

View File

@ -0,0 +1,23 @@
package domain
type Permissions struct {
Permissions []string
}
func (p *Permissions) AppendPermissions(ctxID string, permissions ...string) {
for _, permission := range permissions {
p.appendPermission(ctxID, permission)
}
}
func (p *Permissions) appendPermission(ctxID, permission string) {
if ctxID != "" {
permission = permission + ":" + ctxID
}
for _, existingPermission := range p.Permissions {
if existingPermission == permission {
return
}
}
p.Permissions = append(p.Permissions, permission)
}

View File

@ -1,117 +0,0 @@
package eventstore
import (
"context"
"encoding/json"
"net/http"
"strings"
"sync"
"time"
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
org_model "github.com/caos/zitadel/internal/org/model"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/query"
)
type OrgRepository struct {
Query *query.Queries
SearchLimit uint64
Eventstore v1.Eventstore
Roles []string
SystemDefaults systemdefaults.SystemDefaults
PrefixAvatarURL string
LoginDir http.FileSystem
NotificationDir http.FileSystem
LoginTranslationFileContents map[string][]byte
NotificationTranslationFileContents map[string][]byte
mutex sync.Mutex
supportedLangs []language.Tag
}
func (repo *OrgRepository) OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*org_model.OrgChanges, error) {
changes, err := repo.getOrgChanges(ctx, id, lastSequence, limit, sortAscending, auditLogRetention)
if err != nil {
return nil, err
}
for _, change := range changes.Changes {
change.ModifierName = change.ModifierId
change.ModifierLoginName = change.ModifierId
user, _ := repo.Query.GetUserByID(ctx, change.ModifierId)
if user != nil {
change.ModifierLoginName = user.PreferredLoginName
if user.Human != nil {
change.ModifierName = user.Human.DisplayName
change.ModifierAvatarURL = domain.AvatarURL(repo.PrefixAvatarURL, user.ResourceOwner, user.Human.AvatarKey)
}
if user.Machine != nil {
change.ModifierName = user.Machine.Name
}
}
}
return changes, nil
}
func (repo *OrgRepository) GetOrgMemberRoles(isGlobal bool) []string {
roles := make([]string, 0)
for _, roleMap := range repo.Roles {
if strings.HasPrefix(roleMap, "ORG") {
roles = append(roles, roleMap)
}
}
if isGlobal {
roles = append(roles, domain.RoleSelfManagementGlobal)
}
return roles
}
func (repo *OrgRepository) getOrgChanges(ctx context.Context, orgID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*org_model.OrgChanges, error) {
query := org_view.ChangesQuery(orgID, lastSequence, limit, sortAscending, auditLogRetention)
events, err := repo.Eventstore.FilterEvents(context.Background(), query)
if err != nil {
logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable")
return nil, errors.ThrowInternal(err, "EVENT-328b1", "Errors.Org.NotFound")
}
if len(events) == 0 {
return nil, errors.ThrowNotFound(nil, "EVENT-FpQqK", "Errors.Changes.NotFound")
}
changes := make([]*org_model.OrgChange, len(events))
for i, event := range events {
creationDate, err := ptypes.TimestampProto(event.CreationDate)
logging.Log("EVENT-qxIR7").OnError(err).Debug("unable to parse timestamp")
change := &org_model.OrgChange{
ChangeDate: creationDate,
EventType: event.Type.String(),
ModifierId: event.EditorUser,
Sequence: event.Sequence,
}
if event.Data != nil {
org := new(org_es_model.Org)
err := json.Unmarshal(event.Data, org)
logging.Log("EVENT-XCLEm").OnError(err).Debug("unable to unmarshal data")
change.Data = org
}
changes[i] = change
if lastSequence < event.Sequence {
lastSequence = event.Sequence
}
}
return &org_model.OrgChanges{
Changes: changes,
LastSequence: lastSequence,
}, nil
}

View File

@ -1,204 +0,0 @@
package eventstore
import (
"context"
"encoding/json"
"strings"
"time"
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/eventstore/v1/models"
proj_model "github.com/caos/zitadel/internal/project/model"
proj_view "github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/query"
)
type ProjectRepo struct {
v1.Eventstore
Roles []string
IAMID string
PrefixAvatarURL string
Query *query.Queries
}
func (repo *ProjectRepo) ProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*proj_model.ProjectChanges, error) {
changes, err := repo.getProjectChanges(ctx, id, lastSequence, limit, sortAscending, retention)
if err != nil {
return nil, err
}
for _, change := range changes.Changes {
change.ModifierName = change.ModifierId
change.ModifierLoginName = change.ModifierId
user, _ := repo.Query.GetUserByID(ctx, change.ModifierId)
if user != nil {
change.ModifierLoginName = user.PreferredLoginName
if user.Human != nil {
change.ModifierName = user.Human.DisplayName
change.ModifierAvatarURL = domain.AvatarURL(repo.PrefixAvatarURL, user.ResourceOwner, user.Human.AvatarKey)
}
if user.Machine != nil {
change.ModifierName = user.Machine.Name
}
}
}
return changes, nil
}
func (repo *ProjectRepo) ApplicationChanges(ctx context.Context, projectID string, appID string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*proj_model.ApplicationChanges, error) {
changes, err := repo.getApplicationChanges(ctx, projectID, appID, lastSequence, limit, sortAscending, retention)
if err != nil {
return nil, err
}
for _, change := range changes.Changes {
change.ModifierName = change.ModifierId
change.ModifierLoginName = change.ModifierId
user, _ := repo.Query.GetUserByID(ctx, change.ModifierId)
if user != nil {
change.ModifierLoginName = user.PreferredLoginName
if user.Human != nil {
change.ModifierName = user.Human.DisplayName
change.ModifierAvatarURL = domain.AvatarURL(repo.PrefixAvatarURL, user.ResourceOwner, user.Human.AvatarKey)
}
if user.Machine != nil {
change.ModifierName = user.Machine.Name
}
}
}
return changes, nil
}
func (repo *ProjectRepo) GetProjectMemberRoles(ctx context.Context) ([]string, error) {
iam, err := repo.Query.IAMByID(ctx, repo.IAMID)
if err != nil {
return nil, err
}
roles := make([]string, 0)
global := authz.GetCtxData(ctx).OrgID == iam.GlobalOrgID
for _, roleMap := range repo.Roles {
if strings.HasPrefix(roleMap, "PROJECT") && !strings.HasPrefix(roleMap, "PROJECT_GRANT") {
if global && !strings.HasSuffix(roleMap, "GLOBAL") {
continue
}
roles = append(roles, roleMap)
}
}
return roles, nil
}
func (repo *ProjectRepo) GetProjectGrantMemberRoles() []string {
roles := make([]string, 0)
for _, roleMap := range repo.Roles {
if strings.HasPrefix(roleMap, "PROJECT_GRANT") {
roles = append(roles, roleMap)
}
}
return roles
}
func (repo *ProjectRepo) getProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*proj_model.ProjectChanges, error) {
query := proj_view.ChangesQuery(id, lastSequence, limit, sortAscending, retention)
events, err := repo.Eventstore.FilterEvents(context.Background(), query)
if err != nil {
logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable")
return nil, caos_errs.ThrowInternal(err, "EVENT-328b1", "Errors.Internal")
}
if len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-FpQqK", "Errors.Changes.NotFound")
}
changes := make([]*proj_model.ProjectChange, len(events))
for i, event := range events {
creationDate, err := ptypes.TimestampProto(event.CreationDate)
logging.Log("EVENT-qxIR7").OnError(err).Debug("unable to parse timestamp")
change := &proj_model.ProjectChange{
ChangeDate: creationDate,
EventType: event.Type.String(),
ModifierId: event.EditorUser,
Sequence: event.Sequence,
}
if event.Data != nil {
var data interface{}
if strings.Contains(change.EventType, "application") {
data = new(proj_model.Application)
} else {
data = new(proj_model.Project)
}
err = json.Unmarshal(event.Data, data)
logging.Log("EVENT-NCkpN").OnError(err).Debug("unable to unmarshal data")
change.Data = data
}
changes[i] = change
if lastSequence < event.Sequence {
lastSequence = event.Sequence
}
}
return &proj_model.ProjectChanges{
Changes: changes,
LastSequence: lastSequence,
}, nil
}
func (repo *ProjectRepo) getProjectEvents(ctx context.Context, id string, sequence uint64) ([]*models.Event, error) {
query, err := proj_view.ProjectByIDQuery(id, sequence)
if err != nil {
return nil, err
}
return repo.Eventstore.FilterEvents(ctx, query)
}
func (repo *ProjectRepo) getApplicationChanges(ctx context.Context, projectID string, appID string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*proj_model.ApplicationChanges, error) {
query := proj_view.ChangesQuery(projectID, lastSequence, limit, sortAscending, retention)
events, err := repo.Eventstore.FilterEvents(ctx, query)
if err != nil {
logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable")
return nil, caos_errs.ThrowInternal(err, "EVENT-sw6Ku", "Errors.Internal")
}
if len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-9IHLP", "Errors.Changes.NotFound")
}
result := make([]*proj_model.ApplicationChange, 0)
for _, event := range events {
if !strings.Contains(event.Type.String(), "application") || event.Data == nil {
continue
}
app := new(proj_model.Application)
err := json.Unmarshal(event.Data, app)
logging.Log("EVENT-GIiKD").OnError(err).Debug("unable to unmarshal data")
if app.AppID != appID {
continue
}
creationDate, err := ptypes.TimestampProto(event.CreationDate)
logging.Log("EVENT-MJzeN").OnError(err).Debug("unable to parse timestamp")
result = append(result, &proj_model.ApplicationChange{
ChangeDate: creationDate,
EventType: event.Type.String(),
ModifierId: event.EditorUser,
Sequence: event.Sequence,
Data: app,
})
if lastSequence < event.Sequence {
lastSequence = event.Sequence
}
}
return &proj_model.ApplicationChanges{
Changes: result,
LastSequence: lastSequence,
}, nil
}

View File

@ -1,101 +0,0 @@
package eventstore
import (
"context"
"time"
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/eventstore/v1/models"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_view "github.com/caos/zitadel/internal/user/repository/view"
)
type UserRepo struct {
v1.Eventstore
Query *query.Queries
SystemDefaults systemdefaults.SystemDefaults
PrefixAvatarURL string
}
func (repo *UserRepo) UserChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*usr_model.UserChanges, error) {
changes, err := repo.getUserChanges(ctx, id, lastSequence, limit, sortAscending, retention)
if err != nil {
return nil, err
}
for _, change := range changes.Changes {
change.ModifierName = change.ModifierID
change.ModifierLoginName = change.ModifierID
user, _ := repo.Query.GetUserByID(ctx, change.ModifierID)
if user != nil {
change.ModifierLoginName = user.PreferredLoginName
if user.Human != nil {
change.ModifierName = user.Human.DisplayName
change.ModifierAvatarURL = domain.AvatarURL(repo.PrefixAvatarURL, user.ResourceOwner, user.Human.AvatarKey)
}
if user.Machine != nil {
change.ModifierName = user.Machine.Name
}
}
}
return changes, nil
}
func (r *UserRepo) getUserChanges(ctx context.Context, userID string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*usr_model.UserChanges, error) {
query := usr_view.ChangesQuery(userID, lastSequence, limit, sortAscending, retention)
events, err := r.Eventstore.FilterEvents(ctx, query)
if err != nil {
logging.Log("EVENT-g9HCv").WithError(err).Warn("eventstore unavailable")
return nil, errors.ThrowInternal(err, "EVENT-htuG9", "Errors.Internal")
}
if len(events) == 0 {
return nil, errors.ThrowNotFound(nil, "EVENT-6cAxe", "Errors.User.NoChanges")
}
result := make([]*usr_model.UserChange, len(events))
for i, event := range events {
creationDate, err := ptypes.TimestampProto(event.CreationDate)
logging.Log("EVENT-8GTGS").OnError(err).Debug("unable to parse timestamp")
change := &usr_model.UserChange{
ChangeDate: creationDate,
EventType: event.Type.String(),
ModifierID: event.EditorUser,
Sequence: event.Sequence,
}
//TODO: now all types should be unmarshalled, e.g. password
// if len(event.Data) != 0 {
// user := new(model.User)
// err := json.Unmarshal(event.Data, user)
// logging.Log("EVENT-Rkg7X").OnError(err).Debug("unable to unmarshal data")
// change.Data = user
// }
result[i] = change
if lastSequence < event.Sequence {
lastSequence = event.Sequence
}
}
return &usr_model.UserChanges{
Changes: result,
LastSequence: lastSequence,
}, nil
}
func (r *UserRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
query, err := usr_view.UserByIDQuery(userID, sequence)
if err != nil {
return nil, err
}
return r.Eventstore.FilterEvents(ctx, query)
}

View File

@ -1,60 +0,0 @@
package eventsourcing
import (
"github.com/caos/logging"
"github.com/rakyll/statik/fs"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/management/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/static"
)
type Config struct {
SearchLimit uint64
Domain string
APIDomain string
Eventstore v1.Config
View types.SQL
}
type EsRepository struct {
eventstore.OrgRepository
eventstore.ProjectRepo
eventstore.UserRepo
}
func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, queries *query.Queries, staticStorage static.Storage) (*EsRepository, error) {
es, err := v1.Start(conf.Eventstore)
if err != nil {
return nil, err
}
assetsAPI := conf.APIDomain + "/assets/v1/"
statikLoginFS, err := fs.NewWithNamespace("login")
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start login statik dir")
statikNotificationFS, err := fs.NewWithNamespace("notification")
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start notification statik dir")
return &EsRepository{
OrgRepository: eventstore.OrgRepository{
SearchLimit: conf.SearchLimit,
Eventstore: es,
Roles: roles,
SystemDefaults: systemDefaults,
PrefixAvatarURL: assetsAPI,
LoginDir: statikLoginFS,
NotificationDir: statikNotificationFS,
LoginTranslationFileContents: make(map[string][]byte),
NotificationTranslationFileContents: make(map[string][]byte),
Query: queries,
},
ProjectRepo: eventstore.ProjectRepo{es, roles, systemDefaults.IamID, assetsAPI, queries},
UserRepo: eventstore.UserRepo{es, queries, systemDefaults, assetsAPI},
}, nil
}

View File

@ -1,14 +0,0 @@
package repository
import (
"context"
"time"
org_model "github.com/caos/zitadel/internal/org/model"
)
type OrgRepository interface {
OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*org_model.OrgChanges, error)
GetOrgMemberRoles(isGlobal bool) []string
}

View File

@ -1,18 +0,0 @@
package repository
import (
"context"
"time"
"github.com/caos/zitadel/internal/project/model"
)
type ProjectRepository interface {
GetProjectMemberRoles(ctx context.Context) ([]string, error)
ProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*model.ProjectChanges, error)
ApplicationChanges(ctx context.Context, projectID string, appID string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*model.ApplicationChanges, error)
GetProjectGrantMemberRoles() []string
}

View File

@ -1,7 +0,0 @@
package repository
type Repository interface {
ProjectRepository
OrgRepository
UserRepository
}

View File

@ -1,12 +0,0 @@
package repository
import (
"context"
"time"
"github.com/caos/zitadel/internal/user/model"
)
type UserRepository interface {
UserChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*model.UserChanges, error)
}

122
internal/query/changes.go Normal file
View File

@ -0,0 +1,122 @@
package query
import (
"context"
"time"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/repository/user"
"github.com/caos/zitadel/internal/repository/project"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/errors"
)
type Changes struct {
Changes []*Change
}
type Change struct {
ChangeDate time.Time
EventType string
Sequence uint64
ResourceOwner string
ModifierId string
ModifierName string
ModifierLoginName string
ModifierResourceOwner string
ModifierAvatarKey string
}
func (q *Queries) OrgChanges(ctx context.Context, orgID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
query := func(query *eventstore.SearchQuery) {
query.AggregateTypes(org.AggregateType).
AggregateIDs(orgID)
}
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
}
func (q *Queries) ProjectChanges(ctx context.Context, projectID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
query := func(query *eventstore.SearchQuery) {
query.AggregateTypes(project.AggregateType).
AggregateIDs(projectID)
}
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
}
func (q *Queries) ApplicationChanges(ctx context.Context, projectID, appID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
query := func(query *eventstore.SearchQuery) {
query.AggregateTypes(project.AggregateType).
AggregateIDs(projectID).
EventData(map[string]interface{}{
"appId": appID,
})
}
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
}
func (q *Queries) UserChanges(ctx context.Context, userID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
query := func(query *eventstore.SearchQuery) {
query.AggregateTypes(user.AggregateType).
AggregateIDs(userID)
}
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
}
func (q *Queries) changes(ctx context.Context, query func(query *eventstore.SearchQuery), lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
builder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(limit)
if !sortAscending {
builder.OrderDesc()
}
search := builder.AddQuery().SequenceGreater(lastSequence) //always use greater (less is done automatically by sorting desc)
query(search)
events, err := q.eventstore.Filter(ctx, builder)
if err != nil {
logging.Log("QUERY-ZRffs").WithError(err).Warn("eventstore unavailable")
return nil, errors.ThrowInternal(err, "QUERY-328b1", "Errors.Internal")
}
if len(events) == 0 {
return nil, errors.ThrowNotFound(nil, "QUERY-FpQqK", "Errors.Changes.NotFound")
}
changes := make([]*Change, 0, len(events))
for _, event := range events {
if event.CreationDate().Before(time.Now().Add(-auditLogRetention)) {
continue
}
change := &Change{
ChangeDate: event.CreationDate(),
EventType: string(event.Type()),
Sequence: event.Sequence(),
ResourceOwner: event.Aggregate().ResourceOwner,
ModifierId: event.EditorUser(),
ModifierName: event.EditorUser(),
ModifierLoginName: event.EditorUser(),
}
editor, _ := q.GetUserByID(ctx, change.ModifierId)
if editor != nil {
change.ModifierLoginName = editor.PreferredLoginName
change.ModifierResourceOwner = editor.ResourceOwner
if editor.Human != nil {
change.ModifierName = editor.Human.DisplayName
change.ModifierAvatarKey = editor.Human.AvatarKey
}
if editor.Machine != nil {
change.ModifierName = editor.Machine.Name
}
}
changes = append(changes, change)
}
if len(changes) == 0 {
return nil, errors.ThrowPreconditionFailed(nil, "QUERY-DEGS2", "Errors.Changes.AuditRetention")
}
return &Changes{
Changes: changes,
}, nil
}

View File

@ -1,27 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/model"
)
func readModelToIAM(readModel *ReadModel) *model.IAM {
return &model.IAM{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel),
GlobalOrgID: readModel.GlobalOrgID,
IAMProjectID: readModel.ProjectID,
SetUpDone: readModel.SetUpDone,
SetUpStarted: readModel.SetUpStarted,
}
}
func readModelToObjectRoot(readModel eventstore.ReadModel) models.ObjectRoot {
return models.ObjectRoot{
AggregateID: readModel.AggregateID,
ChangeDate: readModel.ChangeDate,
CreationDate: readModel.CreationDate,
ResourceOwner: readModel.ResourceOwner,
Sequence: readModel.ProcessedSequence,
}
}

View File

@ -1,55 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMIDPConfigReadModel struct {
IDPConfigReadModel
iamID string
configID string
}
func NewIAMIDPConfigReadModel(iamID, configID string) *IAMIDPConfigReadModel {
return &IAMIDPConfigReadModel{
iamID: iamID,
configID: configID,
}
}
func (rm *IAMIDPConfigReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.IDPConfigAddedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigAddedEvent)
case *iam.IDPConfigChangedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigChangedEvent)
case *iam.IDPConfigDeactivatedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigDeactivatedEvent)
case *iam.IDPConfigReactivatedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigReactivatedEvent)
case *iam.IDPConfigRemovedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigRemovedEvent)
case *iam.IDPOIDCConfigAddedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.OIDCConfigAddedEvent)
case *iam.IDPOIDCConfigChangedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.OIDCConfigChangedEvent)
case *iam.IDPJWTConfigAddedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.JWTConfigAddedEvent)
case *iam.IDPJWTConfigChangedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.JWTConfigChangedEvent)
}
}
}
func (rm *IAMIDPConfigReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
AddQuery().
AggregateTypes(iam.AggregateType).
AggregateIDs(rm.iamID).
EventData(map[string]interface{}{
"idpConfigId": rm.configID,
}).Builder()
}

View File

@ -1,31 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMIDPConfigsReadModel struct {
IDPConfigsReadModel
}
func (rm *IAMIDPConfigsReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.IDPConfigAddedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigAddedEvent)
case *iam.IDPConfigChangedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigChangedEvent)
case *iam.IDPConfigDeactivatedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigDeactivatedEvent)
case *iam.IDPConfigReactivatedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigReactivatedEvent)
case *iam.IDPConfigRemovedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigRemovedEvent)
case *iam.IDPOIDCConfigAddedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.OIDCConfigAddedEvent)
case *iam.IDPOIDCConfigChangedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.OIDCConfigChangedEvent)
}
}
}

View File

@ -1,45 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/member"
)
type IAMMemberReadModel struct {
MemberReadModel
userID string
iamID string
}
func NewIAMMemberReadModel(iamID, userID string) *IAMMemberReadModel {
return &IAMMemberReadModel{
iamID: iamID,
userID: userID,
}
}
func (rm *IAMMemberReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.MemberAddedEvent:
rm.MemberReadModel.AppendEvents(&e.MemberAddedEvent)
case *iam.MemberChangedEvent:
rm.MemberReadModel.AppendEvents(&e.MemberChangedEvent)
case *member.MemberAddedEvent, *member.MemberChangedEvent,
*iam.MemberRemovedEvent, *iam.MemberCascadeRemovedEvent:
rm.MemberReadModel.AppendEvents(e)
}
}
}
func (rm *IAMMemberReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
AddQuery().
AggregateTypes(iam.AggregateType).
AggregateIDs(rm.iamID).
EventData(map[string]interface{}{
"userId": rm.userID,
}).Builder()
}

View File

@ -1,25 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMMembersReadModel struct {
MembersReadModel
}
func (rm *IAMMembersReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.MemberAddedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberAddedEvent)
case *iam.MemberChangedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberChangedEvent)
case *iam.MemberRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberRemovedEvent)
case *iam.MemberCascadeRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}

View File

@ -1,136 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/member"
"github.com/caos/zitadel/internal/repository/policy"
)
type ReadModel struct {
eventstore.ReadModel
SetUpStarted domain.Step
SetUpDone domain.Step
Members IAMMembersReadModel
IDPs IAMIDPConfigsReadModel
GlobalOrgID string
ProjectID string
DefaultLoginPolicy IAMLoginPolicyReadModel
DefaultLabelPolicy IAMLabelPolicyReadModel
DefaultOrgIAMPolicy IAMOrgIAMPolicyReadModel
DefaultPasswordComplexityPolicy IAMPasswordComplexityPolicyReadModel
DefaultPasswordAgePolicy IAMPasswordAgePolicyReadModel
DefaultPasswordLockoutPolicy IAMLockoutPolicyReadModel
}
func NewReadModel(id string) *ReadModel {
return &ReadModel{
ReadModel: eventstore.ReadModel{
AggregateID: id,
},
}
}
func (rm *ReadModel) IDPByID(idpID string) *IAMIDPConfigReadModel {
_, config := rm.IDPs.ConfigByID(idpID)
if config == nil {
return nil
}
return &IAMIDPConfigReadModel{IDPConfigReadModel: *config}
}
func (rm *ReadModel) AppendEvents(events ...eventstore.Event) {
rm.ReadModel.AppendEvents(events...)
for _, event := range events {
switch event.(type) {
case *member.MemberAddedEvent,
*member.MemberChangedEvent,
*member.MemberRemovedEvent:
rm.Members.AppendEvents(event)
case *iam.IDPConfigAddedEvent,
*iam.IDPConfigChangedEvent,
*iam.IDPConfigDeactivatedEvent,
*iam.IDPConfigReactivatedEvent,
*iam.IDPConfigRemovedEvent,
*iam.IDPOIDCConfigAddedEvent,
*iam.IDPOIDCConfigChangedEvent:
rm.IDPs.AppendEvents(event)
case *policy.LabelPolicyAddedEvent,
*policy.LabelPolicyChangedEvent:
rm.DefaultLabelPolicy.AppendEvents(event)
case *policy.LoginPolicyAddedEvent,
*policy.LoginPolicyChangedEvent:
rm.DefaultLoginPolicy.AppendEvents(event)
case *policy.OrgIAMPolicyAddedEvent:
rm.DefaultOrgIAMPolicy.AppendEvents(event)
case *policy.PasswordComplexityPolicyAddedEvent,
*policy.PasswordComplexityPolicyChangedEvent:
rm.DefaultPasswordComplexityPolicy.AppendEvents(event)
case *policy.PasswordAgePolicyAddedEvent,
*policy.PasswordAgePolicyChangedEvent:
rm.DefaultPasswordAgePolicy.AppendEvents(event)
case *policy.LockoutPolicyAddedEvent,
*policy.LockoutPolicyChangedEvent:
rm.DefaultPasswordLockoutPolicy.AppendEvents(event)
}
}
}
func (rm *ReadModel) Reduce() (err error) {
for _, event := range rm.Events {
switch e := event.(type) {
case *iam.ProjectSetEvent:
rm.ProjectID = e.ProjectID
case *iam.GlobalOrgSetEvent:
rm.GlobalOrgID = e.OrgID
case *iam.SetupStepEvent:
if e.Done {
rm.SetUpDone = e.Step
} else {
rm.SetUpStarted = e.Step
}
}
}
for _, reduce := range []func() error{
rm.Members.Reduce,
rm.IDPs.Reduce,
rm.DefaultLoginPolicy.Reduce,
rm.DefaultLabelPolicy.Reduce,
rm.DefaultOrgIAMPolicy.Reduce,
rm.DefaultPasswordComplexityPolicy.Reduce,
rm.DefaultPasswordAgePolicy.Reduce,
rm.DefaultPasswordLockoutPolicy.Reduce,
rm.ReadModel.Reduce,
} {
if err = reduce(); err != nil {
return err
}
}
return nil
}
func (rm *ReadModel) AppendAndReduce(events ...eventstore.Event) error {
rm.AppendEvents(events...)
return rm.Reduce()
}
func (rm *ReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
AddQuery().
AggregateTypes(iam.AggregateType).
AggregateIDs(rm.AggregateID).
Builder()
}

View File

@ -1,22 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
)
type IAMLabelPolicyReadModel struct{ LabelPolicyReadModel }
func (rm *IAMLabelPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.LabelPolicyAddedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyAddedEvent)
case *iam.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyChangedEvent)
case *policy.LabelPolicyAddedEvent, *policy.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,22 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
)
type IAMLoginPolicyReadModel struct{ LoginPolicyReadModel }
func (rm *IAMLoginPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicyAddedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyAddedEvent)
case *iam.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyChangedEvent)
case *policy.LoginPolicyAddedEvent, *policy.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,20 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
)
type IAMOrgIAMPolicyReadModel struct{ OrgIAMPolicyReadModel }
func (rm *IAMOrgIAMPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *policy.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,26 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
)
type IAMPasswordAgePolicyReadModel struct {
PasswordAgePolicyReadModel
}
func (rm *IAMPasswordAgePolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordAgePolicyAddedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(&e.PasswordAgePolicyAddedEvent)
case *iam.PasswordAgePolicyChangedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(&e.PasswordAgePolicyChangedEvent)
case *policy.PasswordAgePolicyAddedEvent,
*policy.PasswordAgePolicyChangedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,26 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
)
type IAMPasswordComplexityPolicyReadModel struct {
PasswordComplexityPolicyReadModel
}
func (rm *IAMPasswordComplexityPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordComplexityPolicyAddedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(&e.PasswordComplexityPolicyAddedEvent)
case *iam.PasswordComplexityPolicyChangedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(&e.PasswordComplexityPolicyChangedEvent)
case *policy.PasswordComplexityPolicyAddedEvent,
*policy.PasswordComplexityPolicyChangedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,24 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
)
type IAMLockoutPolicyReadModel struct {
LockoutPolicyReadModel
}
func (rm *IAMLockoutPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *iam.LockoutPolicyAddedEvent:
rm.LockoutPolicyReadModel.AppendEvents(&e.LockoutPolicyAddedEvent)
case *iam.LockoutPolicyChangedEvent:
rm.LockoutPolicyReadModel.AppendEvents(&e.LockoutPolicyChangedEvent)
case *policy.LockoutPolicyAddedEvent, *policy.LockoutPolicyChangedEvent:
rm.LockoutPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,111 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/idpconfig"
)
type IDPConfigReadModel struct {
eventstore.ReadModel
State domain.IDPConfigState
ConfigID string
Name string
AutoRegister bool
StylingType domain.IDPConfigStylingType
ProviderType domain.IdentityProviderType
OIDCConfig *OIDCConfigReadModel
JWTConfig *JWTConfigReadModel
}
func NewIDPConfigReadModel(configID string) *IDPConfigReadModel {
return &IDPConfigReadModel{
ConfigID: configID,
}
}
func (rm *IDPConfigReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *idpconfig.IDPConfigAddedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigChangedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigDeactivatedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigReactivatedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigRemovedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.OIDCConfigAddedEvent:
rm.OIDCConfig = &OIDCConfigReadModel{}
rm.ReadModel.AppendEvents(e)
rm.OIDCConfig.AppendEvents(event)
case *idpconfig.OIDCConfigChangedEvent:
rm.ReadModel.AppendEvents(e)
rm.OIDCConfig.AppendEvents(event)
case *idpconfig.JWTConfigAddedEvent:
rm.JWTConfig = &JWTConfigReadModel{}
rm.ReadModel.AppendEvents(e)
rm.JWTConfig.AppendEvents(event)
case *idpconfig.JWTConfigChangedEvent:
rm.ReadModel.AppendEvents(e)
rm.JWTConfig.AppendEvents(event)
}
}
}
func (rm *IDPConfigReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *idpconfig.IDPConfigAddedEvent:
rm.reduceConfigAddedEvent(e)
case *idpconfig.IDPConfigChangedEvent:
rm.reduceConfigChangedEvent(e)
case *idpconfig.IDPConfigDeactivatedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateInactive)
case *idpconfig.IDPConfigReactivatedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateActive)
case *idpconfig.IDPConfigRemovedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateRemoved)
}
}
if rm.OIDCConfig != nil {
if err := rm.OIDCConfig.Reduce(); err != nil {
return err
}
}
if rm.JWTConfig != nil {
if err := rm.JWTConfig.Reduce(); err != nil {
return err
}
}
return rm.ReadModel.Reduce()
}
func (rm *IDPConfigReadModel) reduceConfigAddedEvent(e *idpconfig.IDPConfigAddedEvent) {
rm.ConfigID = e.ConfigID
rm.Name = e.Name
rm.StylingType = e.StylingType
rm.State = domain.IDPConfigStateActive
rm.AutoRegister = e.AutoRegister
}
func (rm *IDPConfigReadModel) reduceConfigChangedEvent(e *idpconfig.IDPConfigChangedEvent) {
if e.Name != nil {
rm.Name = *e.Name
}
if e.StylingType != nil && e.StylingType.Valid() {
rm.StylingType = *e.StylingType
}
if e.AutoRegister != nil {
rm.AutoRegister = *e.AutoRegister
}
}
func (rm *IDPConfigReadModel) reduceConfigStateChanged(configID string, state domain.IDPConfigState) {
rm.State = state
}

View File

@ -1,64 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/idpconfig"
)
type IDPConfigsReadModel struct {
eventstore.ReadModel
Configs []*IDPConfigReadModel
}
func (rm *IDPConfigsReadModel) ConfigByID(id string) (idx int, config *IDPConfigReadModel) {
for idx, config = range rm.Configs {
if config.ConfigID == id {
return idx, config
}
}
return -1, nil
}
func (rm *IDPConfigsReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *idpconfig.IDPConfigAddedEvent:
config := NewIDPConfigReadModel(e.ConfigID)
rm.Configs = append(rm.Configs, config)
config.AppendEvents(event)
case *idpconfig.IDPConfigChangedEvent:
_, config := rm.ConfigByID(e.ConfigID)
config.AppendEvents(e)
case *idpconfig.IDPConfigDeactivatedEvent:
_, config := rm.ConfigByID(e.ConfigID)
config.AppendEvents(e)
case *idpconfig.IDPConfigReactivatedEvent:
_, config := rm.ConfigByID(e.ConfigID)
config.AppendEvents(e)
case *idpconfig.OIDCConfigAddedEvent:
_, config := rm.ConfigByID(e.IDPConfigID)
config.AppendEvents(e)
case *idpconfig.OIDCConfigChangedEvent:
_, config := rm.ConfigByID(e.IDPConfigID)
config.AppendEvents(e)
case *idpconfig.IDPConfigRemovedEvent:
idx, _ := rm.ConfigByID(e.ConfigID)
if idx < 0 {
continue
}
copy(rm.Configs[idx:], rm.Configs[idx+1:])
rm.Configs[len(rm.Configs)-1] = nil
rm.Configs = rm.Configs[:len(rm.Configs)-1]
}
}
}
func (rm *IDPConfigsReadModel) Reduce() error {
for _, config := range rm.Configs {
if err := config.Reduce(); err != nil {
return err
}
}
return nil
}

View File

@ -1,47 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/idpconfig"
)
type JWTConfigReadModel struct {
eventstore.ReadModel
IDPConfigID string
JWTEndpoint string
Issuer string
KeysEndpoint string
}
func (rm *JWTConfigReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *idpconfig.JWTConfigAddedEvent:
rm.reduceConfigAddedEvent(e)
case *idpconfig.JWTConfigChangedEvent:
rm.reduceConfigChangedEvent(e)
}
}
return rm.ReadModel.Reduce()
}
func (rm *JWTConfigReadModel) reduceConfigAddedEvent(e *idpconfig.JWTConfigAddedEvent) {
rm.IDPConfigID = e.IDPConfigID
rm.JWTEndpoint = e.JWTEndpoint
rm.Issuer = e.Issuer
rm.KeysEndpoint = e.KeysEndpoint
}
func (rm *JWTConfigReadModel) reduceConfigChangedEvent(e *idpconfig.JWTConfigChangedEvent) {
if e.JWTEndpoint != nil {
rm.JWTEndpoint = *e.JWTEndpoint
}
if e.Issuer != nil {
rm.Issuer = *e.Issuer
}
if e.KeysEndpoint != nil {
rm.KeysEndpoint = *e.KeysEndpoint
}
}

View File

@ -1,11 +1,9 @@
package query package query
import ( import (
"context"
"time" "time"
"github.com/caos/zitadel/internal/query/projection" "github.com/caos/zitadel/internal/query/projection"
"github.com/caos/zitadel/internal/telemetry/tracing"
sq "github.com/Masterminds/squirrel" sq "github.com/Masterminds/squirrel"
) )
@ -63,19 +61,6 @@ type Member struct {
AvatarURL string AvatarURL string
} }
func (r *Queries) IAMMemberByID(ctx context.Context, iamID, userID string) (member *IAMMemberReadModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
member = NewIAMMemberReadModel(iamID, userID)
err = r.eventstore.FilterToQueryReducer(ctx, member)
if err != nil {
return nil, err
}
return member, nil
}
var ( var (
memberTableAlias = table{ memberTableAlias = table{
name: "members", name: "members",

View File

@ -1,35 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/member"
)
//MemberReadModel represenets the default member view.
// It's computed from events.
type MemberReadModel struct {
eventstore.ReadModel
UserID string
Roles []string
}
//NewMemberReadModel is the default constructor of MemberReadModel
func NewMemberReadModel(userID string) *MemberReadModel {
return &MemberReadModel{
UserID: userID,
}
}
//Reduce extends eventstore.MemberReadModel
func (rm *MemberReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *member.MemberAddedEvent:
rm.Roles = e.Roles
case *member.MemberChangedEvent:
rm.Roles = e.Roles
}
}
return rm.ReadModel.Reduce()
}

View File

@ -0,0 +1,60 @@
package query
import (
"context"
"strings"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/domain"
)
func (q *Queries) GetIAMMemberRoles() []string {
roles := make([]string, 0)
for _, roleMap := range q.zitadelRoles {
if strings.HasPrefix(roleMap.Role, "IAM") {
roles = append(roles, roleMap.Role)
}
}
return roles
}
func (q *Queries) GetOrgMemberRoles(isGlobal bool) []string {
roles := make([]string, 0)
for _, roleMap := range q.zitadelRoles {
if strings.HasPrefix(roleMap.Role, "ORG") {
roles = append(roles, roleMap.Role)
}
}
if isGlobal {
roles = append(roles, domain.RoleSelfManagementGlobal)
}
return roles
}
func (q *Queries) GetProjectMemberRoles(ctx context.Context) ([]string, error) {
iam, err := q.IAMByID(ctx, domain.IAMID)
if err != nil {
return nil, err
}
roles := make([]string, 0)
global := authz.GetCtxData(ctx).OrgID == iam.GlobalOrgID
for _, roleMap := range q.zitadelRoles {
if strings.HasPrefix(roleMap.Role, "PROJECT") && !strings.HasPrefix(roleMap.Role, "PROJECT_GRANT") {
if global && !strings.HasSuffix(roleMap.Role, "GLOBAL") {
continue
}
roles = append(roles, roleMap.Role)
}
}
return roles, nil
}
func (q *Queries) GetProjectGrantMemberRoles() []string {
roles := make([]string, 0)
for _, roleMap := range q.zitadelRoles {
if strings.HasPrefix(roleMap.Role, "PROJECT_GRANT") {
roles = append(roles, roleMap.Role)
}
}
return roles
}

View File

@ -1,53 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/member"
)
type MembersReadModel struct {
eventstore.ReadModel
Members []*MemberReadModel
}
func (rm *MembersReadModel) MemberByUserID(id string) (idx int, member *MemberReadModel) {
for idx, member = range rm.Members {
if member.UserID == id {
return idx, member
}
}
return -1, nil
}
func (rm *MembersReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *member.MemberAddedEvent:
m := NewMemberReadModel(e.UserID)
rm.Members = append(rm.Members, m)
m.AppendEvents(e)
case *member.MemberChangedEvent:
_, m := rm.MemberByUserID(e.UserID)
m.AppendEvents(e)
case *member.MemberRemovedEvent:
idx, _ := rm.MemberByUserID(e.UserID)
if idx < 0 {
continue
}
copy(rm.Members[idx:], rm.Members[idx+1:])
rm.Members[len(rm.Members)-1] = nil
rm.Members = rm.Members[:len(rm.Members)-1]
}
}
}
func (rm *MembersReadModel) Reduce() (err error) {
for _, m := range rm.Members {
err = m.Reduce()
if err != nil {
return err
}
}
return rm.ReadModel.Reduce()
}

View File

@ -1,71 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/idpconfig"
)
type OIDCConfigReadModel struct {
eventstore.ReadModel
IDPConfigID string
ClientID string
ClientSecret *crypto.CryptoValue
Issuer string
AuthorizationEndpoint string
TokenEndpoint string
Scopes []string
IDPDisplayNameMapping domain.OIDCMappingField
UserNameMapping domain.OIDCMappingField
}
func (rm *OIDCConfigReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *idpconfig.OIDCConfigAddedEvent:
rm.reduceConfigAddedEvent(e)
case *idpconfig.OIDCConfigChangedEvent:
rm.reduceConfigChangedEvent(e)
}
}
return rm.ReadModel.Reduce()
}
func (rm *OIDCConfigReadModel) reduceConfigAddedEvent(e *idpconfig.OIDCConfigAddedEvent) {
rm.IDPConfigID = e.IDPConfigID
rm.ClientID = e.ClientID
rm.ClientSecret = e.ClientSecret
rm.Issuer = e.Issuer
rm.AuthorizationEndpoint = e.AuthorizationEndpoint
rm.TokenEndpoint = e.TokenEndpoint
rm.Scopes = e.Scopes
rm.IDPDisplayNameMapping = e.IDPDisplayNameMapping
rm.UserNameMapping = e.UserNameMapping
}
func (rm *OIDCConfigReadModel) reduceConfigChangedEvent(e *idpconfig.OIDCConfigChangedEvent) {
if e.ClientID != nil {
rm.ClientID = *e.ClientID
}
if e.Issuer != nil {
rm.Issuer = *e.Issuer
}
if e.AuthorizationEndpoint != nil {
rm.AuthorizationEndpoint = *e.AuthorizationEndpoint
}
if e.TokenEndpoint != nil {
rm.TokenEndpoint = *e.TokenEndpoint
}
if len(e.Scopes) > 0 {
rm.Scopes = e.Scopes
}
if e.IDPDisplayNameMapping != nil && e.IDPDisplayNameMapping.Valid() {
rm.IDPDisplayNameMapping = *e.IDPDisplayNameMapping
}
if e.UserNameMapping != nil && e.UserNameMapping.Valid() {
rm.UserNameMapping = *e.UserNameMapping
}
}

View File

@ -1,38 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
)
type OrgMembersReadModel struct {
MembersReadModel
}
func (rm *OrgMembersReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.MemberAddedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberAddedEvent)
case *org.MemberChangedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberChangedEvent)
case *org.MemberRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberRemovedEvent)
case *org.MemberCascadeRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}
type OrgMemberReadModel MemberReadModel
func (rm *OrgMemberReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.MemberAddedEvent:
rm.ReadModel.AppendEvents(&e.MemberAddedEvent)
case *org.MemberChangedEvent:
rm.ReadModel.AppendEvents(&e.MemberChangedEvent)
}
}
}

View File

@ -1,22 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgLabelPolicyReadModel struct{ LabelPolicyReadModel }
func (rm *OrgLabelPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.LabelPolicyAddedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyAddedEvent)
case *org.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyChangedEvent)
case *policy.LabelPolicyAddedEvent, *policy.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,22 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgLoginPolicyReadModel struct{ LoginPolicyReadModel }
func (rm *OrgLoginPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.LoginPolicyAddedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyAddedEvent)
case *org.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyChangedEvent)
case *policy.LoginPolicyAddedEvent, *policy.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,20 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgOrgIAMPolicyReadModel struct{ OrgIAMPolicyReadModel }
func (rm *OrgOrgIAMPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *policy.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,24 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgPasswordAgePolicyReadModel struct {
PasswordAgePolicyReadModel
}
func (rm *OrgPasswordAgePolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.PasswordAgePolicyAddedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(&e.PasswordAgePolicyAddedEvent)
case *org.PasswordAgePolicyChangedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(&e.PasswordAgePolicyChangedEvent)
case *policy.PasswordAgePolicyAddedEvent, *policy.PasswordAgePolicyChangedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,24 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgPasswordComplexityPolicyReadModel struct {
PasswordComplexityPolicyReadModel
}
func (rm *OrgPasswordComplexityPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.PasswordComplexityPolicyAddedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(&e.PasswordComplexityPolicyAddedEvent)
case *org.PasswordComplexityPolicyChangedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(&e.PasswordComplexityPolicyChangedEvent)
case *policy.PasswordComplexityPolicyAddedEvent, *policy.PasswordComplexityPolicyChangedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,24 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgPasswordLockoutPolicyReadModel struct {
LockoutPolicyReadModel
}
func (rm *OrgPasswordLockoutPolicyReadModel) AppendEvents(events ...eventstore.Event) {
for _, event := range events {
switch e := event.(type) {
case *org.LockoutPolicyAddedEvent:
rm.LockoutPolicyReadModel.AppendEvents(&e.LockoutPolicyAddedEvent)
case *org.LockoutPolicyChangedEvent:
rm.LockoutPolicyReadModel.AppendEvents(&e.LockoutPolicyChangedEvent)
case *policy.LockoutPolicyAddedEvent, *policy.LockoutPolicyChangedEvent:
rm.LockoutPolicyReadModel.AppendEvents(e)
}
}
}

View File

@ -1,65 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/policy"
)
type LabelPolicyReadModel struct {
eventstore.ReadModel
PrimaryColor string
BackgroundColor string
WarnColor string
FontColor string
PrimaryColorDark string
BackgroundColorDark string
WarnColorDark string
FontColorDark string
IsActive bool
}
func (rm *LabelPolicyReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *policy.LabelPolicyAddedEvent:
rm.PrimaryColor = e.PrimaryColor
rm.BackgroundColor = e.BackgroundColor
rm.FontColor = e.FontColor
rm.WarnColor = e.WarnColor
rm.PrimaryColorDark = e.PrimaryColorDark
rm.BackgroundColorDark = e.BackgroundColorDark
rm.FontColorDark = e.FontColorDark
rm.WarnColorDark = e.WarnColorDark
rm.IsActive = true
case *policy.LabelPolicyChangedEvent:
if e.PrimaryColor != nil {
rm.PrimaryColor = *e.PrimaryColor
}
if e.BackgroundColor != nil {
rm.BackgroundColor = *e.BackgroundColor
}
if e.WarnColor != nil {
rm.WarnColor = *e.WarnColor
}
if e.FontColor != nil {
rm.FontColor = *e.FontColor
}
if e.PrimaryColorDark != nil {
rm.PrimaryColorDark = *e.PrimaryColorDark
}
if e.BackgroundColorDark != nil {
rm.BackgroundColorDark = *e.BackgroundColorDark
}
if e.WarnColorDark != nil {
rm.WarnColorDark = *e.WarnColorDark
}
if e.FontColorDark != nil {
rm.FontColorDark = *e.FontColorDark
}
case *policy.LabelPolicyRemovedEvent:
rm.IsActive = false
}
}
return rm.ReadModel.Reduce()
}

View File

@ -1,51 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/policy"
)
type LoginPolicyReadModel struct {
eventstore.ReadModel
AllowUserNamePassword bool
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
PasswordlessType domain.PasswordlessType
IsActive bool
}
func (rm *LoginPolicyReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *policy.LoginPolicyAddedEvent:
rm.AllowUserNamePassword = e.AllowUserNamePassword
rm.AllowExternalIDP = e.AllowExternalIDP
rm.AllowRegister = e.AllowRegister
rm.ForceMFA = e.ForceMFA
rm.PasswordlessType = e.PasswordlessType
rm.IsActive = true
case *policy.LoginPolicyChangedEvent:
if e.AllowUserNamePassword != nil {
rm.AllowUserNamePassword = *e.AllowUserNamePassword
}
if e.AllowExternalIDP != nil {
rm.AllowExternalIDP = *e.AllowExternalIDP
}
if e.AllowRegister != nil {
rm.AllowRegister = *e.AllowRegister
}
if e.ForceMFA != nil {
rm.ForceMFA = *e.ForceMFA
}
if e.PasswordlessType != nil {
rm.PasswordlessType = *e.PasswordlessType
}
case *policy.LoginPolicyRemovedEvent:
rm.IsActive = false
}
}
return rm.ReadModel.Reduce()
}

View File

@ -1,26 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/policy"
)
type OrgIAMPolicyReadModel struct {
eventstore.ReadModel
UserLoginMustBeDomain bool
}
func (rm *OrgIAMPolicyReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *policy.OrgIAMPolicyAddedEvent:
rm.UserLoginMustBeDomain = e.UserLoginMustBeDomain
case *policy.OrgIAMPolicyChangedEvent:
if e.UserLoginMustBeDomain != nil {
rm.UserLoginMustBeDomain = *e.UserLoginMustBeDomain
}
}
}
return rm.ReadModel.Reduce()
}

View File

@ -1,31 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/policy"
)
type PasswordAgePolicyReadModel struct {
eventstore.ReadModel
ExpireWarnDays uint64
MaxAgeDays uint64
}
func (rm *PasswordAgePolicyReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *policy.PasswordAgePolicyAddedEvent:
rm.ExpireWarnDays = e.ExpireWarnDays
rm.MaxAgeDays = e.MaxAgeDays
case *policy.PasswordAgePolicyChangedEvent:
if e.ExpireWarnDays != nil {
rm.ExpireWarnDays = *e.ExpireWarnDays
}
if e.MaxAgeDays != nil {
rm.MaxAgeDays = *e.MaxAgeDays
}
}
}
return rm.ReadModel.Reduce()
}

View File

@ -1,46 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/policy"
)
type PasswordComplexityPolicyReadModel struct {
eventstore.ReadModel
MinLength uint64
HasLowercase bool
HasUpperCase bool
HasNumber bool
HasSymbol bool
}
func (rm *PasswordComplexityPolicyReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *policy.PasswordComplexityPolicyAddedEvent:
rm.MinLength = e.MinLength
rm.HasLowercase = e.HasLowercase
rm.HasUpperCase = e.HasUppercase
rm.HasNumber = e.HasNumber
rm.HasSymbol = e.HasSymbol
case *policy.PasswordComplexityPolicyChangedEvent:
if e.MinLength != nil {
rm.MinLength = *e.MinLength
}
if e.HasLowercase != nil {
rm.HasLowercase = *e.HasLowercase
}
if e.HasUppercase != nil {
rm.HasUpperCase = *e.HasUppercase
}
if e.HasNumber != nil {
rm.HasNumber = *e.HasNumber
}
if e.HasSymbol != nil {
rm.HasSymbol = *e.HasSymbol
}
}
}
return rm.ReadModel.Reduce()
}

View File

@ -1,31 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/policy"
)
type LockoutPolicyReadModel struct {
eventstore.ReadModel
MaxAttempts uint64
ShowLockOutFailures bool
}
func (rm *LockoutPolicyReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *policy.LockoutPolicyAddedEvent:
rm.MaxAttempts = e.MaxPasswordAttempts
rm.ShowLockOutFailures = e.ShowLockOutFailures
case *policy.LockoutPolicyChangedEvent:
if e.MaxPasswordAttempts != nil {
rm.MaxAttempts = *e.MaxPasswordAttempts
}
if e.ShowLockOutFailures != nil {
rm.ShowLockOutFailures = *e.ShowLockOutFailures
}
}
}
return rm.ReadModel.Reduce()
}

View File

@ -7,6 +7,10 @@ import (
"sync" "sync"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/rakyll/statik/fs"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/api/authz"
sd "github.com/caos/zitadel/internal/config/systemdefaults" sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore"
@ -18,8 +22,6 @@ import (
"github.com/caos/zitadel/internal/repository/project" "github.com/caos/zitadel/internal/repository/project"
usr_repo "github.com/caos/zitadel/internal/repository/user" usr_repo "github.com/caos/zitadel/internal/repository/user"
"github.com/caos/zitadel/internal/repository/usergrant" "github.com/caos/zitadel/internal/repository/usergrant"
"github.com/rakyll/statik/fs"
"golang.org/x/text/language"
) )
type Queries struct { type Queries struct {
@ -34,13 +36,14 @@ type Queries struct {
LoginTranslationFileContents map[string][]byte LoginTranslationFileContents map[string][]byte
NotificationTranslationFileContents map[string][]byte NotificationTranslationFileContents map[string][]byte
supportedLangs []language.Tag supportedLangs []language.Tag
zitadelRoles []authz.RoleMapping
} }
type Config struct { type Config struct {
Eventstore types.SQLUser Eventstore types.SQLUser
} }
func StartQueries(ctx context.Context, es *eventstore.Eventstore, projections projection.Config, defaults sd.SystemDefaults, keyChan chan<- interface{}) (repo *Queries, err error) { func StartQueries(ctx context.Context, es *eventstore.Eventstore, projections projection.Config, defaults sd.SystemDefaults, keyChan chan<- interface{}, zitadelRoles []authz.RoleMapping) (repo *Queries, err error) {
sqlClient, err := projections.CRDB.Start() sqlClient, err := projections.CRDB.Start()
if err != nil { if err != nil {
return nil, err return nil, err
@ -61,6 +64,7 @@ func StartQueries(ctx context.Context, es *eventstore.Eventstore, projections pr
NotificationDir: statikNotificationFS, NotificationDir: statikNotificationFS,
LoginTranslationFileContents: make(map[string][]byte), LoginTranslationFileContents: make(map[string][]byte),
NotificationTranslationFileContents: make(map[string][]byte), NotificationTranslationFileContents: make(map[string][]byte),
zitadelRoles: zitadelRoles,
} }
iam_repo.RegisterEventMappers(repo.eventstore) iam_repo.RegisterEventMappers(repo.eventstore)
usr_repo.RegisterEventMappers(repo.eventstore) usr_repo.RegisterEventMappers(repo.eventstore)

View File

@ -13,7 +13,6 @@ import (
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/query/projection" "github.com/caos/zitadel/internal/query/projection"
) )
@ -354,11 +353,6 @@ func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwn
return scan(row) return scan(row)
} }
func (q *Queries) UserEvents(ctx context.Context, orgID, userID string, sequence uint64) ([]eventstore.Event, error) {
query := NewUserEventSearchQuery(userID, orgID, sequence)
return q.eventstore.Filter(ctx, query)
}
func (q *UserSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder { func (q *UserSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
query = q.SearchRequest.toQuery(query) query = q.SearchRequest.toQuery(query)
for _, q := range q.Queries { for _, q := range q.Queries {

View File

@ -185,14 +185,12 @@ var (
} }
) )
func (q *Queries) UserGrantByID(ctx context.Context, id string, queries ...SearchQuery) (*UserGrant, error) { func (q *Queries) UserGrant(ctx context.Context, queries ...SearchQuery) (*UserGrant, error) {
query, scan := prepareUserGrantQuery() query, scan := prepareUserGrantQuery()
for _, q := range queries { for _, q := range queries {
query = q.toQuery(query) query = q.toQuery(query)
} }
stmt, args, err := query.Where(sq.Eq{ stmt, args, err := query.ToSql()
UserGrantID.identifier(): id,
}).ToSql()
if err != nil { if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Fa1KW", "Errors.Query.SQLStatement") return nil, errors.ThrowInternal(err, "QUERY-Fa1KW", "Errors.Query.SQLStatement")
} }

View File

@ -1,67 +0,0 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/user"
)
type UserReadModel struct {
eventstore.ReadModel
}
func NewUserReadModel(id string) *UserReadModel {
return &UserReadModel{
ReadModel: eventstore.ReadModel{
AggregateID: id,
},
}
}
func (rm *UserReadModel) AppendEvents(events ...eventstore.Event) {
rm.ReadModel.AppendEvents(events...)
for _, event := range events {
switch event.(type) {
// TODO: implement append events
}
}
}
func (rm *UserReadModel) Reduce() (err error) {
for _, event := range rm.Events {
switch event.(type) {
//TODO: implement reduce
}
}
for _, reduce := range []func() error{
rm.ReadModel.Reduce,
} {
if err = reduce(); err != nil {
return err
}
}
return nil
}
func (rm *UserReadModel) AppendAndReduce(events ...eventstore.Event) error {
rm.AppendEvents(events...)
return rm.Reduce()
}
func (rm *UserReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
AddQuery().
AggregateTypes(user.AggregateType).
AggregateIDs(rm.AggregateID).
Builder()
}
func NewUserEventSearchQuery(userID, orgID string, sequence uint64) *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(orgID).
AddQuery().
AggregateTypes(user.AggregateType).
AggregateIDs(userID).
SequenceGreater(sequence).
Builder()
}

View File

@ -0,0 +1,42 @@
package query
import (
"context"
"github.com/caos/zitadel/internal/domain"
)
func (q *Queries) MyZitadelPermissions(ctx context.Context, userID string) (*domain.Permissions, error) {
userIDQuery, err := NewMembershipUserIDQuery(userID)
if err != nil {
return nil, err
}
memberships, err := q.Memberships(ctx, &MembershipSearchQuery{
Queries: []SearchQuery{userIDQuery},
})
if err != nil {
return nil, err
}
permissions := &domain.Permissions{Permissions: []string{}}
for _, membership := range memberships.Memberships {
for _, role := range membership.Roles {
permissions = q.mapRoleToPermission(permissions, membership, role)
}
}
return permissions, nil
}
func (q *Queries) mapRoleToPermission(permissions *domain.Permissions, membership *Membership, role string) *domain.Permissions {
for _, mapping := range q.zitadelRoles {
if mapping.Role == role {
ctxID := ""
if membership.Project != nil {
ctxID = membership.Project.ProjectID
} else if membership.ProjectGrant != nil {
ctxID = membership.ProjectGrant.GrantID
}
permissions.AppendPermissions(ctxID, mapping.Permissions...)
}
}
return permissions
}

View File

@ -341,6 +341,7 @@ Errors:
NotExisting: Identitäts Provider Konfiguration existiert nicht NotExisting: Identitäts Provider Konfiguration existiert nicht
Changes: Changes:
NotFound: Es konnte kein Änderungsverlauf gefunden werden NotFound: Es konnte kein Änderungsverlauf gefunden werden
AuditRetention: Änderungsverlauf ist ausserhalb der Audit Log Retention
Token: Token:
NotFound: Token konnte nicht gefunden werden NotFound: Token konnte nicht gefunden werden
UserSession: UserSession:

View File

@ -341,6 +341,7 @@ Errors:
NotExisting: Identity Provider Configuration doesn't exist NotExisting: Identity Provider Configuration doesn't exist
Changes: Changes:
NotFound: No history found NotFound: No history found
AuditRetention: History is outside of the Audit Log Retention
Token: Token:
NotFound: Token not found NotFound: Token not found
UserSession: UserSession:

View File

@ -339,6 +339,7 @@ Errors:
NotExisting: La configurazione del IDP non esiste NotExisting: La configurazione del IDP non esiste
Changes: Changes:
NotFound: Nessuna storia trovata NotFound: Nessuna storia trovata
AuditRetention: La storia è al di fuori della Ritenzione Audit Log
Token: Token:
NotFound: Token non trovato NotFound: Token non trovato
UserSession: UserSession:

View File

@ -638,7 +638,9 @@ message ListMyUserChangesRequest {
} }
message ListMyUserChangesResponse { message ListMyUserChangesResponse {
zitadel.v1.ListDetails details = 1; reserved 1;
reserved "details";
// zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos)
repeated zitadel.change.v1.Change result = 2; repeated zitadel.change.v1.Change result = 2;
} }

View File

@ -2933,7 +2933,9 @@ message ListUserChangesRequest {
} }
message ListUserChangesResponse { message ListUserChangesResponse {
zitadel.v1.ListDetails details = 1; reserved 1;
reserved "details";
// zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos)
repeated zitadel.change.v1.Change result = 2; repeated zitadel.change.v1.Change result = 2;
} }
@ -3449,7 +3451,9 @@ message ListOrgChangesRequest {
} }
message ListOrgChangesResponse { message ListOrgChangesResponse {
zitadel.v1.ListDetails details = 1; reserved 1;
reserved "details";
// zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos)
repeated zitadel.change.v1.Change result = 2; repeated zitadel.change.v1.Change result = 2;
} }
@ -3636,7 +3640,9 @@ message ListProjectChangesRequest {
} }
message ListProjectChangesResponse { message ListProjectChangesResponse {
zitadel.v1.ListDetails details = 1; reserved 1;
reserved "details";
// zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos)
repeated zitadel.change.v1.Change result = 2; repeated zitadel.change.v1.Change result = 2;
} }
@ -3843,7 +3849,9 @@ message ListAppChangesRequest {
} }
message ListAppChangesResponse { message ListAppChangesResponse {
zitadel.v1.ListDetails details = 1; reserved 1;
reserved "details";
// zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos)
repeated zitadel.change.v1.Change result = 2; repeated zitadel.change.v1.Change result = 2;
} }