mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 16:07:24 +00:00
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:
parent
52da2354a3
commit
e99b7f4972
@ -23,14 +23,13 @@ import (
|
||||
"github.com/caos/zitadel/internal/api/oidc"
|
||||
auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
|
||||
"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/config"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"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/query"
|
||||
"github.com/caos/zitadel/internal/query/projection"
|
||||
@ -64,7 +63,6 @@ type Config struct {
|
||||
AuthZ authz.Config
|
||||
Auth auth_es.Config
|
||||
Admin admin_es.Config
|
||||
Mgmt mgmt_es.Config
|
||||
|
||||
API api.Config
|
||||
UI ui.Config
|
||||
@ -158,10 +156,10 @@ func startZitadel(configPaths []string) {
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
esCommands, err := eventstore.StartWithUser(conf.EventstoreBase, conf.Commands.Eventstore)
|
||||
@ -177,15 +175,15 @@ func startZitadel(configPaths []string) {
|
||||
|
||||
var authRepo *auth_es.EsRepository
|
||||
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")
|
||||
}
|
||||
|
||||
repo := struct {
|
||||
authz_repo.EsRepository
|
||||
authz_repo.Repository
|
||||
query.Queries
|
||||
}{
|
||||
*authZRepo,
|
||||
authZRepo,
|
||||
*queries,
|
||||
}
|
||||
|
||||
@ -215,33 +213,27 @@ func startUI(ctx context.Context, conf *Config, authRepo *auth_es.EsRepository,
|
||||
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{}) {
|
||||
roles := make([]string, len(conf.InternalAuthZ.RolePermissionMappings))
|
||||
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)
|
||||
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{}) {
|
||||
repo, err := admin_es.Start(ctx, conf.Admin, conf.SystemDefaults, command, static, *localDevMode)
|
||||
logging.Log("API-D42tq").OnError(err).Fatal("error starting auth repo")
|
||||
|
||||
apis := api.Create(conf.API, conf.InternalAuthZ, query, authZRepo, authRepo, repo, conf.SystemDefaults)
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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())
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -246,53 +246,8 @@ Admin:
|
||||
BulkLimit: 10000
|
||||
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:
|
||||
Domain: $ZITADEL_API_DOMAIN
|
||||
GRPC:
|
||||
ServerPort: 50001
|
||||
GatewayPort: 50002
|
||||
|
@ -1042,8 +1042,7 @@ This is an empty request
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.change.v1.Change | - | |
|
||||
| result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
|
||||
|
||||
|
||||
|
||||
|
@ -5179,8 +5179,7 @@ This is an empty response
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.change.v1.Change | - | |
|
||||
| result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
|
||||
|
||||
|
||||
|
||||
@ -5453,8 +5452,7 @@ This is an empty response
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.change.v1.Change | - | |
|
||||
| result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
|
||||
|
||||
|
||||
|
||||
@ -5568,8 +5566,7 @@ This is an empty request
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.change.v1.Change | - | |
|
||||
| result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
|
||||
|
||||
|
||||
|
||||
@ -5759,8 +5756,7 @@ This is an empty request
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.change.v1.Change | - | |
|
||||
| result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -3,9 +3,6 @@ package eventsourcing
|
||||
import (
|
||||
"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/spooler"
|
||||
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
@ -28,11 +25,10 @@ type Config struct {
|
||||
|
||||
type EsRepository struct {
|
||||
spooler *es_spol.Spooler
|
||||
eventstore.IAMRepository
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
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{
|
||||
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{
|
||||
View: view,
|
||||
},
|
||||
|
@ -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
|
||||
}
|
@ -4,6 +4,5 @@ import "context"
|
||||
|
||||
type Repository interface {
|
||||
Health(ctx context.Context) error
|
||||
IAMRepository
|
||||
AdministratorRepository
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
http_util "github.com/caos/zitadel/internal/api/http"
|
||||
"github.com/caos/zitadel/internal/api/oidc"
|
||||
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/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
@ -29,8 +29,9 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
GRPC grpc_util.Config
|
||||
OIDC oidc.OPHandlerConfig
|
||||
GRPC grpc_util.Config
|
||||
OIDC oidc.OPHandlerConfig
|
||||
Domain string
|
||||
}
|
||||
|
||||
type API struct {
|
||||
@ -58,16 +59,16 @@ type admin interface {
|
||||
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{
|
||||
serverPort: config.GRPC.ServerPort,
|
||||
}
|
||||
|
||||
repo := struct {
|
||||
authz_es.EsRepository
|
||||
authz_repo.Repository
|
||||
query.Queries
|
||||
}{
|
||||
*authZRepo,
|
||||
authZRepo,
|
||||
*q,
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
"github.com/caos/zitadel/internal/management/repository"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
)
|
||||
@ -28,7 +27,6 @@ type Handler struct {
|
||||
commands *command.Commands
|
||||
authInterceptor *http_mw.AuthInterceptor
|
||||
idGenerator id.Generator
|
||||
orgRepo repository.OrgRepository
|
||||
query *query.Queries
|
||||
}
|
||||
|
||||
@ -74,7 +72,6 @@ func NewHandler(
|
||||
authConfig authz.Config,
|
||||
idGenerator id.Generator,
|
||||
storage static.Storage,
|
||||
orgRepo repository.OrgRepository,
|
||||
queries *query.Queries,
|
||||
) http.Handler {
|
||||
h := &Handler{
|
||||
@ -83,7 +80,6 @@ func NewHandler(
|
||||
authInterceptor: http_mw.AuthorizationInterceptor(verifier, authConfig),
|
||||
idGenerator: idGenerator,
|
||||
storage: storage,
|
||||
orgRepo: orgRepo,
|
||||
query: queries,
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
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{
|
||||
Roles: roles,
|
||||
Details: object.ToListDetails(uint64(len(roles)), 0, time.Now()),
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ type Server struct {
|
||||
admin.UnimplementedAdminServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
iam repository.IAMRepository
|
||||
administrator repository.AdministratorRepository
|
||||
iamDomain string
|
||||
assetsAPIDomain string
|
||||
@ -36,7 +35,6 @@ func CreateServer(command *command.Commands, query *query.Queries, repo reposito
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
iam: repo,
|
||||
administrator: repo,
|
||||
iamDomain: iamDomain,
|
||||
assetsAPIDomain: assetsAPIDomain,
|
||||
|
@ -3,28 +3,43 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
obj_grpc "github.com/caos/zitadel/internal/api/grpc/object"
|
||||
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"
|
||||
)
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &auth_pb.ListMyZitadelPermissionsResponse{
|
||||
Result: perms,
|
||||
Result: perms.Permissions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &auth_pb.ListMyProjectPermissionsResponse{
|
||||
Result: perms,
|
||||
Result: userGrant.Roles,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||
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) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -41,7 +45,7 @@ func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserReques
|
||||
if err != nil {
|
||||
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 {
|
||||
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) {
|
||||
sequence, limit, asc := change.ChangeQueryToModel(req.Query)
|
||||
sequence, limit, asc := change.ChangeQueryToQuery(req.Query)
|
||||
features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).ResourceOwner)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &auth_pb.ListMyUserChangesResponse{
|
||||
Result: change.UserChangesToPb(changes.Changes),
|
||||
Result: change.ChangesToPb(changes.Changes, s.assetsAPIDomain),
|
||||
}, 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) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &auth_pb.ListMyUserGrantsResponse{
|
||||
Result: UserGrantsToPb(res.Result),
|
||||
Result: UserGrantsToPb(res.UserGrants),
|
||||
Details: obj_grpc.ToListDetails(
|
||||
res.TotalResult,
|
||||
res.Count,
|
||||
res.Sequence,
|
||||
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
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ids := make([]string, 0, len(grants))
|
||||
for _, grant := range grants {
|
||||
ids := make([]string, 0, len(grants.UserGrants))
|
||||
for _, grant := range grants.UserGrants {
|
||||
ids = appendIfNotExists(ids, grant.ResourceOwner)
|
||||
}
|
||||
|
||||
@ -276,7 +292,7 @@ func MemberTypeToDomain(m *query.Membership) (_ domain.MemberType, displayName,
|
||||
return domain.MemberTypeUnspecified, "", "", ""
|
||||
}
|
||||
|
||||
func userGrantsToIDs(userGrants []*grant_model.UserGrantView) []string {
|
||||
func userGrantsToIDs(userGrants []*query.UserGrant) []string {
|
||||
converted := make([]string, len(userGrants))
|
||||
for i, grant := range userGrants {
|
||||
converted[i] = grant.ID
|
||||
|
@ -1,21 +1,33 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"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"
|
||||
)
|
||||
|
||||
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)
|
||||
return &model.UserGrantSearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
userGrantUserID, err := query.NewUserGrantUserIDSearchQuery(authz.GetCtxData(ctx).UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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))
|
||||
for i, grant := range grants {
|
||||
userGrants[i] = UserGrantToPb(grant)
|
||||
@ -23,13 +35,13 @@ func UserGrantsToPb(grants []*model.UserGrantView) []*auth_pb.UserGrant {
|
||||
return userGrants
|
||||
}
|
||||
|
||||
func UserGrantToPb(grant *model.UserGrantView) *auth_pb.UserGrant {
|
||||
func UserGrantToPb(grant *query.UserGrant) *auth_pb.UserGrant {
|
||||
return &auth_pb.UserGrant{
|
||||
GrantId: grant.ID,
|
||||
OrgId: grant.ResourceOwner,
|
||||
OrgName: grant.OrgName,
|
||||
ProjectId: grant.ProjectID,
|
||||
UserId: grant.UserID,
|
||||
Roles: grant.RoleKeys,
|
||||
Roles: grant.Roles,
|
||||
}
|
||||
}
|
||||
|
@ -1,100 +1,39 @@
|
||||
package change
|
||||
|
||||
import (
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||
user_model "github.com/caos/zitadel/internal/user/model"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
change_pb "github.com/caos/zitadel/pkg/grpc/change"
|
||||
"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 {
|
||||
return 0, 0, false
|
||||
}
|
||||
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))
|
||||
for i, change := range changes {
|
||||
c[i] = UserChangeToPb(change)
|
||||
c[i] = ChangeToPb(change, assetAPIPrefix)
|
||||
}
|
||||
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{
|
||||
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 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,
|
||||
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 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
|
||||
EditorAvatarUrl: domain.AvatarURL(assetAPIPrefix, change.ModifierResourceOwner, change.ModifierAvatarKey),
|
||||
ResourceOwnerId: change.ResourceOwner,
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.ListOrgChangesResponse{
|
||||
Result: change_grpc.OrgChangesToPb(response.Changes),
|
||||
Result: change_grpc.ChangesToPb(response.Changes, s.assetAPIPrefix),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ func (s *Server) ListOrgMemberRoles(ctx context.Context, req *mgmt_pb.ListOrgMem
|
||||
if err != nil {
|
||||
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{
|
||||
Result: roles,
|
||||
}, nil
|
||||
|
@ -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) {
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.ListProjectChangesResponse{
|
||||
Result: change_grpc.ProjectChangesToPb(res.Changes),
|
||||
Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix),
|
||||
}, 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) {
|
||||
roles, err := s.project.GetProjectMemberRoles(ctx)
|
||||
roles, err := s.query.GetProjectMemberRoles(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -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) {
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.ListAppChangesResponse{
|
||||
Result: change_grpc.AppChangesToPb(res.Changes),
|
||||
Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
roles := s.project.GetProjectGrantMemberRoles()
|
||||
roles := s.query.GetProjectGrantMemberRoles()
|
||||
return &mgmt_pb.ListProjectGrantMemberRolesResponse{
|
||||
Result: roles,
|
||||
Details: object_grpc.ToListDetails(uint64(len(roles)), 0, time.Now()),
|
||||
|
@ -7,8 +7,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/api/grpc/server"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"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/pkg/grpc/management"
|
||||
)
|
||||
@ -23,24 +21,14 @@ type Server struct {
|
||||
management.UnimplementedManagementServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
project repository.ProjectRepository
|
||||
org repository.OrgRepository
|
||||
user repository.UserRepository
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
assetAPIPrefix string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Repository eventsourcing.Config
|
||||
}
|
||||
|
||||
func CreateServer(command *command.Commands, query *query.Queries, repo repository.Repository, sd systemdefaults.SystemDefaults, assetAPIPrefix string) *Server {
|
||||
func CreateServer(command *command.Commands, query *query.Queries, sd systemdefaults.SystemDefaults, assetAPIPrefix string) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
project: repo,
|
||||
org: repo,
|
||||
user: repo,
|
||||
systemDefaults: sd,
|
||||
assetAPIPrefix: assetAPIPrefix,
|
||||
}
|
||||
|
@ -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) {
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.ListUserChangesResponse{
|
||||
Result: change_grpc.UserChangesToPb(res.Changes),
|
||||
Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,15 @@ import (
|
||||
)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grant, err := s.query.UserGrantByID(ctx, req.GrantId, ownerQuery)
|
||||
grant, err := s.query.UserGrant(ctx, idQuery, ownerQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -108,7 +107,14 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr
|
||||
UserID: 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) {
|
||||
@ -293,13 +299,23 @@ func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID strin
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
projectRoles := make(map[string]map[string]string)
|
||||
for _, requestedRole := range requestedRoles {
|
||||
for _, grant := range grants {
|
||||
for _, grant := range grants.UserGrants {
|
||||
checkGrantedRoles(projectRoles, grant, requestedRole)
|
||||
}
|
||||
}
|
||||
@ -335,8 +351,8 @@ func (o *OPStorage) assertUserResourceOwner(ctx context.Context, userID string)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func checkGrantedRoles(roles map[string]map[string]string, grant *grant_model.UserGrantView, requestedRole string) {
|
||||
for _, grantedRole := range grant.RoleKeys {
|
||||
func checkGrantedRoles(roles map[string]map[string]string, grant *query.UserGrant, requestedRole string) {
|
||||
for _, grantedRole := range grant.Roles {
|
||||
if requestedRole == grantedRole {
|
||||
appendRole(roles, grantedRole, grant.ResourceOwner, grant.OrgPrimaryDomain)
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type ApplicationRepository interface {
|
||||
AuthorizeClientIDSecret(ctx context.Context, clientID, secret string) error
|
||||
}
|
@ -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)
|
||||
}
|
@ -24,7 +24,6 @@ import (
|
||||
user_model "github.com/caos/zitadel/internal/user/model"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/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 {
|
||||
@ -104,7 +103,7 @@ type orgViewProvider interface {
|
||||
|
||||
type userGrantProvider interface {
|
||||
ProjectByOIDCClientID(context.Context, string) (*query.Project, error)
|
||||
UserGrantsByProjectAndUserID(string, string) ([]*grant_view_model.UserGrantView, error)
|
||||
UserGrantsByProjectAndUserID(string, string) ([]*query.UserGrant, error)
|
||||
}
|
||||
|
||||
type projectProvider interface {
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
user_model "github.com/caos/zitadel/internal/user/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"
|
||||
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
|
||||
)
|
||||
|
||||
type mockViewNoUserSession struct{}
|
||||
@ -216,10 +215,10 @@ func (m *mockUserGrants) ProjectByOIDCClientID(ctx context.Context, s string) (*
|
||||
return &query.Project{ProjectRoleCheck: m.roleCheck}, nil
|
||||
}
|
||||
|
||||
func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*grant_view_model.UserGrantView, error) {
|
||||
var grants []*grant_view_model.UserGrantView
|
||||
func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*query.UserGrant, error) {
|
||||
var grants []*query.UserGrant
|
||||
if m.userGrants > 0 {
|
||||
grants = make([]*grant_view_model.UserGrantView, m.userGrants)
|
||||
grants = make([]*query.UserGrant, m.userGrants)
|
||||
}
|
||||
return grants, nil
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -39,9 +39,6 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
|
||||
handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount, es}),
|
||||
newToken(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount, es}),
|
||||
newUserGrant(
|
||||
handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es},
|
||||
systemDefaults.IamID),
|
||||
newIDPConfig(
|
||||
handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}),
|
||||
newIDPProvider(
|
||||
|
@ -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
|
||||
}
|
@ -3,17 +3,14 @@ package eventsourcing
|
||||
import (
|
||||
"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/spooler"
|
||||
auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"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"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
es2 "github.com/caos/zitadel/internal/eventstore"
|
||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||
es_spol "github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
@ -37,13 +34,11 @@ type EsRepository struct {
|
||||
eventstore.AuthRequestRepo
|
||||
eventstore.TokenRepo
|
||||
eventstore.RefreshTokenRepo
|
||||
eventstore.ApplicationRepo
|
||||
eventstore.UserSessionRepo
|
||||
eventstore.UserGrantRepo
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -83,10 +78,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
|
||||
PrefixAvatarURL: assetsAPI,
|
||||
}
|
||||
//TODO: remove as soon as possible
|
||||
queryView := struct {
|
||||
*query.Queries
|
||||
*auth_view.View
|
||||
}{
|
||||
queryView := queryViewWrapper{
|
||||
queries,
|
||||
view,
|
||||
}
|
||||
@ -131,22 +123,9 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
|
||||
SearchLimit: conf.SearchLimit,
|
||||
KeyAlgorithm: keyAlgorithm,
|
||||
},
|
||||
eventstore.ApplicationRepo{
|
||||
Commands: command,
|
||||
Query: queries,
|
||||
},
|
||||
|
||||
eventstore.UserSessionRepo{
|
||||
View: view,
|
||||
},
|
||||
eventstore.UserGrantRepo{
|
||||
SearchLimit: conf.SearchLimit,
|
||||
View: view,
|
||||
IamID: systemDefaults.IamID,
|
||||
Auth: authZ,
|
||||
AuthZRepo: authZRepo,
|
||||
Query: queries,
|
||||
},
|
||||
eventstore.OrgRepository{
|
||||
SearchLimit: conf.SearchLimit,
|
||||
View: view,
|
||||
@ -157,6 +136,27 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
|
||||
}, 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 {
|
||||
if err := repo.UserRepo.Health(ctx); err != nil {
|
||||
return err
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -9,9 +9,7 @@ type Repository interface {
|
||||
UserRepository
|
||||
AuthRequestRepository
|
||||
TokenRepository
|
||||
ApplicationRepository
|
||||
UserSessionRepository
|
||||
UserGrantRepository
|
||||
OrgRepository
|
||||
RefreshTokenRepository
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
package authz
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/authz/repository"
|
||||
"github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
@ -13,6 +11,6 @@ type Config struct {
|
||||
Repository eventsourcing.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config, authZ authz.Config, systemDefaults sd.SystemDefaults, queries *query.Queries) (*eventsourcing.EsRepository, error) {
|
||||
return eventsourcing.Start(config.Repository, authZ, systemDefaults, queries)
|
||||
func Start(config Config, systemDefaults sd.SystemDefaults, queries *query.Queries) (repository.Repository, error) {
|
||||
return eventsourcing.Start(config.Repository, systemDefaults, queries)
|
||||
}
|
||||
|
@ -14,9 +14,6 @@ import (
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
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/query"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
@ -33,7 +30,7 @@ type TokenVerifierRepo struct {
|
||||
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)
|
||||
if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
|
||||
return nil, viewErr
|
||||
@ -82,7 +79,7 @@ func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenStrin
|
||||
if len(splittedToken) != 2 {
|
||||
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 {
|
||||
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)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
iam, err := repo.getIAMByID(ctx)
|
||||
iam, err := repo.Query.IAMByID(ctx, domain.IAMID)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@ -261,23 +258,6 @@ func (r *TokenVerifierRepo) getUserEvents(ctx context.Context, userID string, se
|
||||
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 {
|
||||
features, err := repo.Query.DefaultFeatures(ctx)
|
||||
if err != nil {
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -3,19 +3,17 @@ package eventsourcing
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
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"
|
||||
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/eventstore"
|
||||
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/spooler"
|
||||
authz_view "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"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"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@ -26,11 +24,11 @@ type Config struct {
|
||||
|
||||
type EsRepository struct {
|
||||
spooler *es_spol.Spooler
|
||||
eventstore.UserGrantRepo
|
||||
eventstore.UserMembershipRepo
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -56,16 +54,12 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, qu
|
||||
|
||||
return &EsRepository{
|
||||
spool,
|
||||
eventstore.UserGrantRepo{
|
||||
View: view,
|
||||
IamID: systemDefaults.IamID,
|
||||
Auth: authZ,
|
||||
Eventstore: es,
|
||||
eventstore.UserMembershipRepo{
|
||||
View: view,
|
||||
},
|
||||
eventstore.TokenVerifierRepo{
|
||||
TokenVerificationKey: keyAlgorithm,
|
||||
Eventstore: es,
|
||||
IAMID: systemDefaults.IamID,
|
||||
View: view,
|
||||
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 {
|
||||
if err := repo.UserGrantRepo.Health(); err != nil {
|
||||
if err := repo.UserMembershipRepo.Health(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -1,10 +1,9 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
import "context"
|
||||
|
||||
type Repository interface {
|
||||
Health(context.Context) error
|
||||
UserGrantRepository
|
||||
UserMembershipRepository
|
||||
TokenVerifierRepository
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ import (
|
||||
)
|
||||
|
||||
type TokenVerifierRepository interface {
|
||||
VerifyAccessToken(ctx context.Context, appName string) (string, string, string, error)
|
||||
ProjectIDByClientID(ctx context.Context, clientID string) (string, error)
|
||||
ExistsOrg(ctx context.Context, orgID string) error
|
||||
VerifyAccessToken(ctx context.Context, tokenString, verifierClientID, projectID string) (userID string, agentID string, clientID, prefLang, resourceOwner string, err error)
|
||||
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
|
||||
CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error
|
||||
VerifierClientID(ctx context.Context, appName string) (clientID, projectID string, err error)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
11
internal/authz/repository/user_membership.go
Normal file
11
internal/authz/repository/user_membership.go
Normal 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)
|
||||
}
|
@ -5,16 +5,15 @@ import (
|
||||
"time"
|
||||
|
||||
"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/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"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/repository/action"
|
||||
iam_repo "github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/keypair"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
@ -71,7 +70,7 @@ func StartCommands(
|
||||
defaults sd.SystemDefaults,
|
||||
authZConfig authz.Config,
|
||||
staticStore static.Storage,
|
||||
authZRepo *authz_repo.EsRepository,
|
||||
authZRepo authz_repo.Repository,
|
||||
) (repo *Commands, err error) {
|
||||
repo = &Commands{
|
||||
eventstore: es,
|
||||
|
23
internal/domain/permission.go
Normal file
23
internal/domain/permission.go
Normal 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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package repository
|
||||
|
||||
type Repository interface {
|
||||
ProjectRepository
|
||||
OrgRepository
|
||||
UserRepository
|
||||
}
|
@ -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
122
internal/query/changes.go
Normal 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
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/query/projection"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
)
|
||||
@ -63,19 +61,6 @@ type Member struct {
|
||||
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 (
|
||||
memberTableAlias = table{
|
||||
name: "members",
|
||||
|
@ -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()
|
||||
}
|
60
internal/query/member_roles.go
Normal file
60
internal/query/member_roles.go
Normal 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
|
||||
}
|
@ -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()
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -7,6 +7,10 @@ import (
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
@ -18,8 +22,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/repository/project"
|
||||
usr_repo "github.com/caos/zitadel/internal/repository/user"
|
||||
"github.com/caos/zitadel/internal/repository/usergrant"
|
||||
"github.com/rakyll/statik/fs"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type Queries struct {
|
||||
@ -34,13 +36,14 @@ type Queries struct {
|
||||
LoginTranslationFileContents map[string][]byte
|
||||
NotificationTranslationFileContents map[string][]byte
|
||||
supportedLangs []language.Tag
|
||||
zitadelRoles []authz.RoleMapping
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -61,6 +64,7 @@ func StartQueries(ctx context.Context, es *eventstore.Eventstore, projections pr
|
||||
NotificationDir: statikNotificationFS,
|
||||
LoginTranslationFileContents: make(map[string][]byte),
|
||||
NotificationTranslationFileContents: make(map[string][]byte),
|
||||
zitadelRoles: zitadelRoles,
|
||||
}
|
||||
iam_repo.RegisterEventMappers(repo.eventstore)
|
||||
usr_repo.RegisterEventMappers(repo.eventstore)
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/query/projection"
|
||||
)
|
||||
|
||||
@ -354,11 +353,6 @@ func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwn
|
||||
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 {
|
||||
query = q.SearchRequest.toQuery(query)
|
||||
for _, q := range q.Queries {
|
||||
|
@ -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()
|
||||
for _, q := range queries {
|
||||
query = q.toQuery(query)
|
||||
}
|
||||
stmt, args, err := query.Where(sq.Eq{
|
||||
UserGrantID.identifier(): id,
|
||||
}).ToSql()
|
||||
stmt, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-Fa1KW", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
42
internal/query/zitadel_permission.go
Normal file
42
internal/query/zitadel_permission.go
Normal 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
|
||||
}
|
@ -341,6 +341,7 @@ Errors:
|
||||
NotExisting: Identitäts Provider Konfiguration existiert nicht
|
||||
Changes:
|
||||
NotFound: Es konnte kein Änderungsverlauf gefunden werden
|
||||
AuditRetention: Änderungsverlauf ist ausserhalb der Audit Log Retention
|
||||
Token:
|
||||
NotFound: Token konnte nicht gefunden werden
|
||||
UserSession:
|
||||
|
@ -341,6 +341,7 @@ Errors:
|
||||
NotExisting: Identity Provider Configuration doesn't exist
|
||||
Changes:
|
||||
NotFound: No history found
|
||||
AuditRetention: History is outside of the Audit Log Retention
|
||||
Token:
|
||||
NotFound: Token not found
|
||||
UserSession:
|
||||
|
@ -339,6 +339,7 @@ Errors:
|
||||
NotExisting: La configurazione del IDP non esiste
|
||||
Changes:
|
||||
NotFound: Nessuna storia trovata
|
||||
AuditRetention: La storia è al di fuori della Ritenzione Audit Log
|
||||
Token:
|
||||
NotFound: Token non trovato
|
||||
UserSession:
|
||||
|
@ -638,7 +638,9 @@ message ListMyUserChangesRequest {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2933,7 +2933,9 @@ message ListUserChangesRequest {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3449,7 +3451,9 @@ message ListOrgChangesRequest {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3636,7 +3640,9 @@ message ListProjectChangesRequest {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3843,7 +3849,9 @@ message ListAppChangesRequest {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user