feat: iam query (#3085)

* fix: only show factors with state ready

* fix: get iam by id and clean up code

* fix: get iam by id and clean up code

* fix: remove unused code
This commit is contained in:
Fabi 2022-01-21 14:01:25 +01:00 committed by GitHub
parent 37d8e23186
commit 01501c5087
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 280 additions and 548 deletions

View File

@ -21,7 +21,6 @@ import (
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/zitadel/internal/telemetry/metrics/otel"
@ -46,7 +45,7 @@ type API struct {
type health interface {
Health(ctx context.Context) error
IAMByID(ctx context.Context, id string) (*iam_model.IAM, error)
IAMByID(ctx context.Context, id string) (*query.IAM, error)
VerifierClientID(ctx context.Context, appName string) (string, string, error)
}
@ -112,10 +111,10 @@ func (a *API) healthHandler() http.Handler {
if err != nil && !errors.IsNotFound(err) {
return errors.ThrowPreconditionFailed(err, "API-dsgT2", "IAM SETUP CHECK FAILED")
}
if iam == nil || iam.SetUpStarted < domain.StepCount-1 {
if iam == nil || iam.SetupStarted < domain.StepCount-1 {
return errors.ThrowPreconditionFailed(nil, "API-HBfs3", "IAM NOT SET UP")
}
if iam.SetUpDone < domain.StepCount-1 {
if iam.SetupDone < domain.StepCount-1 {
return errors.ThrowPreconditionFailed(nil, "API-DASs2", "IAM SETUP RUNNING")
}
return nil

View File

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

View File

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

View File

@ -207,7 +207,7 @@ func (s *Server) SetPrimaryOrgDomain(ctx context.Context, req *mgmt_pb.SetPrimar
}
func (s *Server) ListOrgMemberRoles(ctx context.Context, req *mgmt_pb.ListOrgMemberRolesRequest) (*mgmt_pb.ListOrgMemberRolesResponse, error) {
iam, err := s.iam.IAMByID(ctx, domain.IAMID)
iam, err := s.query.IAMByID(ctx, domain.IAMID)
if err != nil {
return nil, err
}

View File

@ -26,7 +26,6 @@ type Server struct {
project repository.ProjectRepository
org repository.OrgRepository
user repository.UserRepository
iam repository.IamRepository
systemDefaults systemdefaults.SystemDefaults
assetAPIPrefix string
}
@ -42,7 +41,6 @@ func CreateServer(command *command.Commands, query *query.Queries, repo reposito
project: repo,
org: repo,
user: repo,
iam: repo,
systemDefaults: sd,
assetAPIPrefix: assetAPIPrefix,
}

View File

@ -1,38 +0,0 @@
package eventstore
import (
"context"
"net/http"
"github.com/caos/logging"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/iam/model"
)
type IAMRepository struct {
IAMID string
LoginDir http.FileSystem
IAMV2QuerySide *query.Queries
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) GetIAM(ctx context.Context) (*model.IAM, error) {
return repo.IAMV2QuerySide.IAMByID(ctx, repo.IAMID)
}

View File

@ -3,9 +3,6 @@ package eventsourcing
import (
"context"
"github.com/caos/logging"
"github.com/rakyll/statik/fs"
"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"
@ -44,7 +41,6 @@ type EsRepository struct {
eventstore.UserSessionRepo
eventstore.UserGrantRepo
eventstore.OrgRepository
eventstore.IAMRepository
}
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) {
@ -76,9 +72,6 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
return nil, err
}
statikLoginFS, err := fs.NewWithNamespace("login")
logging.Log("CONFI-20opp").OnError(err).Panic("unable to start login statik dir")
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, queries)
userRepo := eventstore.UserRepo{
@ -161,11 +154,6 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co
Eventstore: es,
Query: queries,
},
eventstore.IAMRepository{
IAMID: systemDefaults.IamID,
LoginDir: statikLoginFS,
IAMV2QuerySide: queries,
},
}, nil
}

View File

@ -1,14 +0,0 @@
package repository
import (
"context"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/iam/model"
)
type IAMRepository interface {
Languages(ctx context.Context) ([]language.Tag, error)
GetIAM(ctx context.Context) (*model.IAM, error)
}

View File

@ -13,6 +13,5 @@ type Repository interface {
UserSessionRepository
UserGrantRepository
OrgRepository
IAMRepository
RefreshTokenRepository
}

View File

@ -1,35 +0,0 @@
package eventsourcing
import (
"github.com/caos/logging"
"github.com/caos/zitadel/internal/cache"
"github.com/caos/zitadel/internal/cache/config"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
)
type IAMCache struct {
iamCache cache.Cache
}
func StartCache(conf *config.CacheConfig) (*IAMCache, error) {
iamCache, err := conf.Config.NewCache()
logging.Log("EVENT-9siew").OnError(err).Panic("unable to create iam cache")
return &IAMCache{iamCache: iamCache}, nil
}
func (c *IAMCache) getIAM(ID string) *model.IAM {
user := &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: ID}}
if err := c.iamCache.Get(ID, user); err != nil {
logging.Log("EVENT-slo9x").WithError(err).Debug("error in getting cache")
}
return user
}
func (c *IAMCache) cacheIAM(iam *model.IAM) {
err := c.iamCache.Set(iam.AggregateID, iam)
if err != nil {
logging.Log("EVENT-os03w").WithError(err).Debug("error in setting iam cache")
}
}

View File

@ -1,11 +0,0 @@
package eventsourcing
import (
"github.com/caos/zitadel/internal/cache/config"
"github.com/caos/zitadel/internal/eventstore/v1"
)
type IAMConfig struct {
v1.Eventstore
Cache *config.CacheConfig
}

View File

@ -1,30 +0,0 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
)
func IAMByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
if id == "" {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-0soe4", "Errors.IAM.IDMissing")
}
return IAMQuery(latestSequence).
AggregateIDFilter(id), nil
}
func IAMQuery(latestSequence uint64) *es_models.SearchQuery {
return es_models.NewSearchQuery().
AggregateTypeFilter(model.IAMAggregate).
LatestSequenceFilter(latestSequence)
}
func IAMAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, iam *model.IAM) (*es_models.Aggregate, error) {
if iam == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-lo04e", "Errors.Internal")
}
return aggCreator.NewAggregate(ctx, iam.AggregateID, model.IAMAggregate, model.IAMVersion, iam.Sequence)
}

View File

@ -1,96 +0,0 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
func GetCustomTexts(db *gorm.DB, table string, aggregateID, template, lang string) ([]*model.CustomTextView, error) {
texts := make([]*model.CustomTextView, 0)
queries := []*iam_model.CustomTextSearchQuery{
{
Key: iam_model.CustomTextSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
{
Key: iam_model.CustomTextSearchKeyTemplate,
Value: template,
Method: domain.SearchMethodEquals,
},
{
Key: iam_model.CustomTextSearchKeyLanguage,
Value: lang,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.CustomTextSearchRequest{Queries: queries})
_, err := query(db, &texts)
if err != nil {
return nil, err
}
return texts, nil
}
func GetCustomTextsByAggregateIDAndTemplate(db *gorm.DB, table string, aggregateID, template string) ([]*model.CustomTextView, error) {
texts := make([]*model.CustomTextView, 0)
queries := []*iam_model.CustomTextSearchQuery{
{
Key: iam_model.CustomTextSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
{
Key: iam_model.CustomTextSearchKeyTemplate,
Value: template,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.CustomTextSearchRequest{Queries: queries})
_, err := query(db, &texts)
if err != nil {
return nil, err
}
return texts, nil
}
func CustomTextByIDs(db *gorm.DB, table, aggregateID, template, lang, key string) (*model.CustomTextView, error) {
customText := new(model.CustomTextView)
aggregateIDQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
textTypeQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyTemplate, Value: template, Method: domain.SearchMethodEquals}
languageQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyLanguage, Value: lang, Method: domain.SearchMethodEquals}
keyQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyKey, Value: key, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, textTypeQuery, languageQuery, keyQuery)
err := query(db, customText)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-8nUU3", "Errors.CustomCustomText.NotExisting")
}
return customText, err
}
func PutCustomText(db *gorm.DB, table string, customText *model.CustomTextView) error {
save := repository.PrepareSave(table)
return save(db, customText)
}
func DeleteCustomText(db *gorm.DB, table, aggregateID, template, lang, key string) error {
aggregateIDSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyAggregateID), Value: aggregateID}
templateSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyTemplate), Value: template}
languageSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyLanguage), Value: lang}
keySearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyKey), Value: key}
delete := repository.PrepareDeleteByKeys(table, aggregateIDSearch, templateSearch, keySearch, languageSearch)
return delete(db)
}
func DeleteCustomTextTemplate(db *gorm.DB, table, aggregateID, template, lang string) error {
aggregateIDSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyAggregateID), Value: aggregateID}
templateSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyTemplate), Value: template}
languageSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyLanguage), Value: lang}
delete := repository.PrepareDeleteByKeys(table, aggregateIDSearch, templateSearch, languageSearch)
return delete(db)
}

View File

@ -1,77 +0,0 @@
package view
import (
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
"github.com/jinzhu/gorm"
)
func IAMMemberByIDs(db *gorm.DB, table, orgID, userID string) (*model.IAMMemberView, error) {
member := new(model.IAMMemberView)
iamIDQuery := &model.IAMMemberSearchQuery{Key: iam_model.IAMMemberSearchKeyIamID, Value: orgID, Method: domain.SearchMethodEquals}
userIDQuery := &model.IAMMemberSearchQuery{Key: iam_model.IAMMemberSearchKeyUserID, Value: userID, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, iamIDQuery, userIDQuery)
err := query(db, member)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-Ahq2s", "Errors.IAM.MemberNotExisting")
}
return member, err
}
func SearchIAMMembers(db *gorm.DB, table string, req *iam_model.IAMMemberSearchRequest) ([]*model.IAMMemberView, uint64, error) {
members := make([]*model.IAMMemberView, 0)
query := repository.PrepareSearchQuery(table, model.IAMMemberSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &members)
if err != nil {
return nil, 0, err
}
return members, count, nil
}
func IAMMembersByUserID(db *gorm.DB, table string, userID string) ([]*model.IAMMemberView, error) {
members := make([]*model.IAMMemberView, 0)
queries := []*iam_model.IAMMemberSearchQuery{
{
Key: iam_model.IAMMemberSearchKeyUserID,
Value: userID,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.IAMMemberSearchRequest{Queries: queries})
_, err := query(db, &members)
if err != nil {
return nil, err
}
return members, nil
}
func PutIAMMember(db *gorm.DB, table string, role *model.IAMMemberView) error {
save := repository.PrepareSave(table)
return save(db, role)
}
func PutIAMMembers(db *gorm.DB, table string, members ...*model.IAMMemberView) error {
save := repository.PrepareBulkSave(table)
m := make([]interface{}, len(members))
for i, member := range members {
m[i] = member
}
return save(db, m...)
}
func DeleteIAMMember(db *gorm.DB, table, orgID, userID string) error {
member, err := IAMMemberByIDs(db, table, orgID, userID)
if err != nil {
return err
}
delete := repository.PrepareDeleteByObject(table, member)
return delete(db)
}
func DeleteIAMMembersByUserID(db *gorm.DB, table, userID string) error {
delete := repository.PrepareDeleteByKey(table, model.IAMMemberSearchKey(iam_model.IAMMemberSearchKeyUserID), userID)
return delete(db)
}

View File

@ -1,54 +0,0 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
func GetMessageTexts(db *gorm.DB, table string, aggregateID string) ([]*model.MessageTextView, error) {
texts := make([]*model.MessageTextView, 0)
queries := []*iam_model.MessageTextSearchQuery{
{
Key: iam_model.MessageTextSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.MessageTextSearchRequest{Queries: queries})
_, err := query(db, &texts)
if err != nil {
return nil, err
}
return texts, nil
}
func GetMessageTextByIDs(db *gorm.DB, table, aggregateID, textType, lang string) (*model.MessageTextView, error) {
mailText := new(model.MessageTextView)
aggregateIDQuery := &model.MessageTextSearchQuery{Key: iam_model.MessageTextSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
textTypeQuery := &model.MessageTextSearchQuery{Key: iam_model.MessageTextSearchKeyMessageTextType, Value: textType, Method: domain.SearchMethodEquals}
languageQuery := &model.MessageTextSearchQuery{Key: iam_model.MessageTextSearchKeyLanguage, Value: lang, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, textTypeQuery, languageQuery)
err := query(db, mailText)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-IiJjm", "Errors.IAM.CustomMessageText.NotExisting")
}
return mailText, err
}
func PutMessageText(db *gorm.DB, table string, mailText *model.MessageTextView) error {
save := repository.PrepareSave(table)
return save(db, mailText)
}
func DeleteMessageText(db *gorm.DB, table, aggregateID, textType, lang string) error {
aggregateIDSearch := repository.Key{Key: model.MessageTextSearchKey(iam_model.MessageTextSearchKeyAggregateID), Value: aggregateID}
textTypeSearch := repository.Key{Key: model.MessageTextSearchKey(iam_model.MessageTextSearchKeyMessageTextType), Value: textType}
languageSearch := repository.Key{Key: model.MessageTextSearchKey(iam_model.MessageTextSearchKeyLanguage), Value: lang}
delete := repository.PrepareDeleteByKeys(table, aggregateIDSearch, textTypeSearch, languageSearch)
return delete(db)
}

View File

@ -1,80 +0,0 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
func GetMetadataList(db *gorm.DB, table string, aggregateID string) ([]*model.MetadataView, error) {
metadatas := make([]*model.MetadataView, 0)
queries := []*domain.MetadataSearchQuery{
{
Key: domain.MetadataSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.MetadataSearchRequest{Queries: queries})
_, err := query(db, &metadatas)
if err != nil {
return nil, err
}
return metadatas, nil
}
func MetadataByKey(db *gorm.DB, table, aggregateID, key string) (*model.MetadataView, error) {
metadata := new(model.MetadataView)
aggregateIDQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
keyQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyKey, Value: key, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, keyQuery)
err := query(db, metadata)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-m0pes", "Errors.Metadata.NotExisting")
}
return metadata, err
}
func MetadataByKeyAndResourceOwner(db *gorm.DB, table, aggregateID, resourceOwner, key string) (*model.MetadataView, error) {
metadata := new(model.MetadataView)
aggregateIDQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
resourceOwnerQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyResourceOwner, Value: resourceOwner, Method: domain.SearchMethodEquals}
keyQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyKey, Value: key, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, resourceOwnerQuery, keyQuery)
err := query(db, metadata)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-29kkd", "Errors.Metadata.NotExisting")
}
return metadata, err
}
func SearchMetadata(db *gorm.DB, table string, req *domain.MetadataSearchRequest) ([]*model.MetadataView, uint64, error) {
metadata := make([]*model.MetadataView, 0)
query := repository.PrepareSearchQuery(table, model.MetadataSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &metadata)
if err != nil {
return nil, 0, err
}
return metadata, count, nil
}
func PutMetadata(db *gorm.DB, table string, customText *model.MetadataView) error {
save := repository.PrepareSave(table)
return save(db, customText)
}
func DeleteMetadata(db *gorm.DB, table, aggregateID, key string) error {
aggregateIDQuery := repository.Key{Key: model.MetadataSearchKey(domain.MetadataSearchKeyAggregateID), Value: aggregateID}
keyQuery := repository.Key{Key: model.MetadataSearchKey(domain.MetadataSearchKeyKey), Value: key}
deleteMD := repository.PrepareDeleteByKeys(table, aggregateIDQuery, keyQuery)
return deleteMD(db)
}
func DeleteMetadataByAggregateID(db *gorm.DB, table, aggregateID string) error {
aggregateIDQuery := repository.Key{Key: model.MetadataSearchKey(domain.MetadataSearchKeyAggregateID), Value: aggregateID}
deleteMD := repository.PrepareDeleteByKeys(table, aggregateIDQuery)
return deleteMD(db)
}

View File

@ -1,16 +0,0 @@
package eventstore
import (
"context"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/query"
)
type IAMRepository struct {
IAMV2Query *query.Queries
}
func (repo *IAMRepository) IAMByID(ctx context.Context, id string) (*iam_model.IAM, error) {
return repo.IAMV2Query.IAMByID(ctx, id)
}

View File

@ -16,7 +16,6 @@ import (
"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/i18n"
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"
@ -38,18 +37,6 @@ type OrgRepository struct {
supportedLangs []language.Tag
}
func (repo *OrgRepository) 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 *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 {

View File

@ -24,7 +24,6 @@ type EsRepository struct {
eventstore.OrgRepository
eventstore.ProjectRepo
eventstore.UserRepo
eventstore.IAMRepository
}
func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, queries *query.Queries, staticStorage static.Storage) (*EsRepository, error) {
@ -57,6 +56,5 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, querie
},
ProjectRepo: eventstore.ProjectRepo{es, roles, systemDefaults.IamID, assetsAPI, queries},
UserRepo: eventstore.UserRepo{es, queries, systemDefaults, assetsAPI},
IAMRepository: eventstore.IAMRepository{IAMV2Query: queries},
}, nil
}

View File

@ -1,10 +0,0 @@
package repository
import (
"context"
iam_model "github.com/caos/zitadel/internal/iam/model"
)
type IamRepository interface {
IAMByID(ctx context.Context, id string) (*iam_model.IAM, error)
}

View File

@ -4,13 +4,10 @@ import (
"context"
"time"
"golang.org/x/text/language"
org_model "github.com/caos/zitadel/internal/org/model"
)
type OrgRepository interface {
Languages(ctx context.Context) ([]language.Tag, error)
OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*org_model.OrgChanges, error)
GetOrgMemberRoles(isGlobal bool) []string

View File

@ -4,5 +4,4 @@ type Repository interface {
ProjectRepository
OrgRepository
UserRepository
IamRepository
}

View File

@ -1,10 +0,0 @@
package view
import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
)
func (v *View) MessageTextByIDs(aggregateID, textType, lang, messageTextTableVar string) (*model.MessageTextView, error) {
return view.GetMessageTextByIDs(v.Db, messageTextTableVar, aggregateID, textType, lang)
}

116
internal/query/iam.go Normal file
View File

@ -0,0 +1,116 @@
package query
import (
"context"
"database/sql"
errs "errors"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/query/projection"
)
var (
iamTable = table{
name: projection.IAMProjectionTable,
}
IAMColumnID = Column{
name: projection.IAMColumnID,
table: iamTable,
}
IAMColumnChangeDate = Column{
name: projection.IAMColumnChangeDate,
table: iamTable,
}
IAMColumnSequence = Column{
name: projection.IAMColumnSequence,
table: iamTable,
}
IAMColumnGlobalOrgID = Column{
name: projection.IAMColumnGlobalOrgID,
table: iamTable,
}
IAMColumnProjectID = Column{
name: projection.IAMColumnProjectID,
table: iamTable,
}
IAMColumnSetupStarted = Column{
name: projection.IAMColumnSetUpStarted,
table: iamTable,
}
IAMColumnSetupDone = Column{
name: projection.IAMColumnSetUpDone,
table: iamTable,
}
)
type IAM struct {
ID string
ChangeDate time.Time
Sequence uint64
GlobalOrgID string
IAMProjectID string
SetupStarted domain.Step
SetupDone domain.Step
}
type IAMSearchQueries struct {
SearchRequest
Queries []SearchQuery
}
func (q *IAMSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
query = q.SearchRequest.toQuery(query)
for _, q := range q.Queries {
query = q.toQuery(query)
}
return query
}
func (q *Queries) IAMByID(ctx context.Context, id string) (*IAM, error) {
stmt, scan := prepareIAMQuery()
query, args, err := stmt.Where(sq.Eq{
IAMColumnID.identifier(): id,
}).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-d9ngs", "Errors.Query.SQLStatement")
}
row := q.client.QueryRowContext(ctx, query, args...)
return scan(row)
}
func prepareIAMQuery() (sq.SelectBuilder, func(*sql.Row) (*IAM, error)) {
return sq.Select(
IAMColumnID.identifier(),
IAMColumnChangeDate.identifier(),
IAMColumnSequence.identifier(),
IAMColumnGlobalOrgID.identifier(),
IAMColumnProjectID.identifier(),
IAMColumnSetupStarted.identifier(),
IAMColumnSetupDone.identifier(),
).
From(iamTable.identifier()).PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*IAM, error) {
o := new(IAM)
err := row.Scan(
&o.ID,
&o.ChangeDate,
&o.Sequence,
&o.GlobalOrgID,
&o.IAMProjectID,
&o.SetupStarted,
&o.SetupDone,
)
if err != nil {
if errs.Is(err, sql.ErrNoRows) {
return nil, errors.ThrowNotFound(err, "QUERY-n0wng", "Errors.IAM.NotFound")
}
return nil, errors.ThrowInternal(err, "QUERY-d9nw", "Errors.Internal")
}
return o, nil
}
}

124
internal/query/iam_test.go Normal file
View File

@ -0,0 +1,124 @@
package query
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"regexp"
"testing"
"github.com/caos/zitadel/internal/domain"
errs "github.com/caos/zitadel/internal/errors"
)
func Test_IAMPrepares(t *testing.T) {
type want struct {
sqlExpectations sqlExpectation
err checkErr
}
tests := []struct {
name string
prepare interface{}
want want
object interface{}
}{
{
name: "prepareIAMQuery no result",
prepare: prepareIAMQuery,
want: want{
sqlExpectations: mockQueries(
regexp.QuoteMeta(`SELECT zitadel.projections.iam.id,`+
` zitadel.projections.iam.change_date,`+
` zitadel.projections.iam.sequence,`+
` zitadel.projections.iam.global_org_id,`+
` zitadel.projections.iam.iam_project_id,`+
` zitadel.projections.iam.setup_started,`+
` zitadel.projections.iam.setup_done`+
` FROM zitadel.projections.iam`),
nil,
nil,
),
err: func(err error) (error, bool) {
if !errs.IsNotFound(err) {
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
}
return nil, true
},
},
object: (*IAM)(nil),
},
{
name: "prepareIAMQuery found",
prepare: prepareIAMQuery,
want: want{
sqlExpectations: mockQuery(
regexp.QuoteMeta(`SELECT zitadel.projections.iam.id,`+
` zitadel.projections.iam.change_date,`+
` zitadel.projections.iam.sequence,`+
` zitadel.projections.iam.global_org_id,`+
` zitadel.projections.iam.iam_project_id,`+
` zitadel.projections.iam.setup_started,`+
` zitadel.projections.iam.setup_done`+
` FROM zitadel.projections.iam`),
[]string{
"id",
"change_date",
"sequence",
"global_org_id",
"iam_project_id",
"setup_started",
"setup_done",
},
[]driver.Value{
"id",
testNow,
uint64(20211108),
"global-org-id",
"project-id",
domain.Step2,
domain.Step1,
},
),
},
object: &IAM{
ID: "id",
ChangeDate: testNow,
Sequence: 20211108,
GlobalOrgID: "global-org-id",
IAMProjectID: "project-id",
SetupStarted: domain.Step2,
SetupDone: domain.Step1,
},
},
{
name: "prepareIAMQuery sql err",
prepare: prepareIAMQuery,
want: want{
sqlExpectations: mockQueryErr(
regexp.QuoteMeta(`SELECT zitadel.projections.iam.id,`+
` zitadel.projections.iam.change_date,`+
` zitadel.projections.iam.sequence,`+
` zitadel.projections.iam.global_org_id,`+
` zitadel.projections.iam.iam_project_id,`+
` zitadel.projections.iam.setup_started,`+
` zitadel.projections.iam.setup_done`+
` FROM zitadel.projections.iam`),
sql.ErrConnDone,
),
err: func(err error) (error, bool) {
if !errors.Is(err, sql.ErrConnDone) {
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
}
return nil, true
},
},
object: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
})
}
}

View File

@ -0,0 +1,21 @@
package query
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/i18n"
"golang.org/x/text/language"
)
func (q *Queries) Languages(ctx context.Context) ([]language.Tag, error) {
if len(q.supportedLangs) == 0 {
langs, err := i18n.SupportedLanguages(q.LoginDir)
if err != nil {
logging.Log("ADMIN-tiMWs").WithError(err).Debug("unable to parse language")
return nil, err
}
q.supportedLangs = langs
}
return q.supportedLangs, nil
}

View File

@ -10,7 +10,6 @@ import (
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/eventstore"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/query/projection"
"github.com/caos/zitadel/internal/repository/action"
iam_repo "github.com/caos/zitadel/internal/repository/iam"
@ -19,7 +18,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/caos/zitadel/internal/telemetry/tracing"
"github.com/rakyll/statik/fs"
"golang.org/x/text/language"
)
@ -35,6 +33,7 @@ type Queries struct {
mutex sync.Mutex
LoginTranslationFileContents map[string][]byte
NotificationTranslationFileContents map[string][]byte
supportedLangs []language.Tag
}
type Config struct {
@ -78,25 +77,3 @@ func StartQueries(ctx context.Context, es *eventstore.Eventstore, projections pr
return repo, nil
}
func (r *Queries) IAMByID(ctx context.Context, id string) (_ *iam_model.IAM, err error) {
readModel, err := r.iamByID(ctx, id)
if err != nil {
return nil, err
}
return readModelToIAM(readModel), nil
}
func (r *Queries) iamByID(ctx context.Context, id string) (_ *ReadModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
readModel := NewReadModel(id)
err = r.eventstore.FilterToQueryReducer(ctx, readModel)
if err != nil {
return nil, err
}
return readModel, nil
}

View File

@ -16,7 +16,7 @@ func (l *Login) customExternalUserMapping(ctx context.Context, user *domain.Exte
resourceOwner = config.AggregateID
}
if resourceOwner == domain.IAMID {
iam, err := l.authRepo.GetIAM(ctx)
iam, err := l.query.IAMByID(ctx, domain.IAMID)
if err != nil {
return nil, err
}

View File

@ -203,7 +203,7 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R
if errors.IsNotFound(err) {
err = nil
}
iam, err := l.authRepo.GetIAM(r.Context())
iam, err := l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err)
return
@ -248,13 +248,13 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R
l.renderNextStep(w, r, authReq)
}
func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *iam_model.IAM, orgIAMPolicy *query.OrgIAMPolicy, human *domain.Human, externalIDP *domain.UserIDPLink, err error) {
func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *query.IAM, orgIAMPolicy *query.OrgIAMPolicy, human *domain.Human, externalIDP *domain.UserIDPLink, err error) {
var errID, errMessage string
if err != nil {
errID, errMessage = l.getErrorMessage(r, err)
}
if orgIAMPolicy == nil {
iam, err = l.authRepo.GetIAM(r.Context())
iam, err = l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderError(w, r, authReq, err)
return
@ -335,7 +335,7 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http
}
func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
iam, err := l.authRepo.GetIAM(r.Context())
iam, err := l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err)
return

View File

@ -111,7 +111,7 @@ func (l *Login) handleExternalRegisterCallback(w http.ResponseWriter, r *http.Re
}
func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) {
iam, err := l.authRepo.GetIAM(r.Context())
iam, err := l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
@ -137,7 +137,7 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
l.registerExternalUser(w, r, authReq, iam, user, externalIDP)
}
func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *iam_model.IAM, user *domain.Human, externalIDP *domain.UserIDPLink) {
func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *query.IAM, user *domain.Human, externalIDP *domain.UserIDPLink) {
resourceOwner := iam.GlobalOrgID
memberRoles := []string{domain.RoleSelfManagementGlobal}
@ -194,7 +194,7 @@ func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Reque
return
}
iam, err := l.authRepo.GetIAM(r.Context())
iam, err := l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return

View File

@ -61,7 +61,7 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
l.renderRegister(w, r, authRequest, data, err)
return
}
iam, err := l.authRepo.GetIAM(r.Context())
iam, err := l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderRegister(w, r, authRequest, data, err)
return
@ -115,7 +115,7 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
}
if resourceOwner == "" {
iam, err := l.authRepo.GetIAM(r.Context())
iam, err := l.query.IAMByID(r.Context(), domain.IAMID)
if err != nil {
l.renderRegister(w, r, authRequest, formData, err)
return