feat: setup and iam commands (#99)

* start org

* refactor(eventstore): filter in sql for querier

* feat(eventstore): Aggregate precondition

preconditions are checked right before insert. Insert is still transaction save

* feat(eventstore): check preconditions in repository

* test(eventstore): test precondition in models

* test(eventstore): precondition-tests

* start org

* refactor(eventstore): filter in sql for querier

* feat(eventstore): Aggregate precondition

preconditions are checked right before insert. Insert is still transaction save

* feat(admin): start implement org

* feat(eventstore): check preconditions in repository

* fix(eventstore): data as NULL if empty
refactor(eventstore): naming in sequence methods

* feat(admin): org command side

* feat(management): start org-repo

* feat(org): member

* fix: replace ObjectRoot.ID with ObjectRoot.AggregateID

* aggregateID

* add remove,change member

* refactor(org): namings

* refactor(eventstore): querier as type

* fix(precondition): rename validation from precondition to validation

* test(eventstore): isErr func instead of wantErr bool

* fix(tests): Data

* fix(eventstore): correct check for existing events in push,
simplify insert statement

* fix(eventstore): aggregate id public

* test(org): eventsourcing

* test(org): eventstore

* test(org): deactivate, reactivate, orgbyid

* test(org): getMemberByIDs

* tests

* running tests

* add config

* add user repo to admin

* thorw not found if no org found

* iam setup

* eventstore tests done

* setup iam

* lauft

* iam eventstore

* validate if user is already member of org

* modules

* delete unused file

* iam member

* add member validation test

* iam member

* return error if unable to validat member

* generate org id once,
set resourceowner of org

* start iam repo

* set resourceowner on unique aggregates

* setup user const

* better code

* generate files

* fix tests

* Update internal/admin/repository/eventsourcing/repository.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* set ctx data

Co-authored-by: adlerhurst <silvan.reusser@gmail.com>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi 2020-05-18 11:32:16 +02:00 committed by GitHub
parent b9c938594c
commit 8203f2dad3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 16472 additions and 13368 deletions

1
.gitignore vendored
View File

@ -32,3 +32,4 @@ cockroach-data/*
#binaries
cmd/zitadel/zitadel
zitadel

View File

@ -58,4 +58,49 @@ SystemDefaults:
Description: Standard lockout policy
MaxAttempts: 5
ShowLockOutFailures: true
IamID: 'IAM'
SetUp:
GlobalOrg: 'Global'
IAMProject: 'Zitadel'
Orgs:
- Name: 'Global'
Domain: 'global.caos.ch'
Default: true
Users:
- FirstName: 'Global Org'
LastName: 'Administrator'
UserName: 'zitadel-global-org-admin@caos.ch'
Email: 'zitadel-global-org-admin@caos.ch'
Password: 'Password'
Owners:
- 'zitadel-global-org-admin@caos.ch'
- Name: 'CAOS AG'
Domain: 'caos.ch'
Users:
- FirstName: 'Zitadel'
LastName: 'Administrator'
UserName: 'zitadel-admin@caos.ch'
Email: 'zitadel-admin@caos.ch'
Password: 'Password'
Owners:
- 'zitadel-admin@caos.ch'
Projects:
- Name: 'Zitadel'
OIDCApps:
- Name: 'Management-API'
- Name: 'Auth-API'
- Name: 'Admin-API'
- Name: 'Zitadel Console'
RedirectUris:
- '$CITADEL_CONSOLE/auth/callback'
PostLogoutRedirectUris:
- '$CITADEL_CONSOLE/signedout'
ResponseTypes:
- 'CODE'
GrantTypes:
- 'AUTHORIZATION_CODE'
- 'IMPLICIT'
ApplicationType: 'NATIVE'
AuthMethodType: 'AUTH_TYPE_NONE'
Owners:
- 'zitadel-admin@caos.ch'

View File

@ -3,10 +3,14 @@ package eventsourcing
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/setup"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
es_int "github.com/caos/zitadel/internal/eventstore"
es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing"
es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing"
es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
@ -36,9 +40,24 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error)
//conf.Spooler.EsClient = es.Client
//conf.Spooler.SQL = sql
//spool := spooler.StartSpooler(conf.Spooler)
iam, err := es_iam.StartIam(es_iam.IamConfig{
Eventstore: es,
Cache: conf.Eventstore.Cache,
}, systemDefaults)
if err != nil {
return nil, err
}
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
project, err := es_proj.StartProject(es_proj.ProjectConfig{
Eventstore: es,
Cache: conf.Eventstore.Cache,
}, systemDefaults)
if err != nil {
return nil, err
}
user, err := es_usr.StartUser(es_usr.UserConfig{
Eventstore: es,
Cache: conf.Eventstore.Cache,
@ -46,6 +65,11 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error)
if err != nil {
return nil, err
}
eventstoreRepos := setup.EventstoreRepos{OrgEvents: org, UserEvents: user, ProjectEvents: project, IamEvents: iam}
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute()
logging.Log("SERVE-k280HZ").OnError(err).Panic("failed to execute setup")
return &EsRepository{
OrgRepo: eventstore.OrgRepo{
Eventstore: es,

View File

@ -0,0 +1,365 @@
package setup
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
proj_model "github.com/caos/zitadel/internal/project/model"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
type Setup struct {
repos EventstoreRepos
iamID string
setUpConfig types.IAMSetUp
}
type EventstoreRepos struct {
IamEvents *iam_event.IamEventstore
OrgEvents *org_event.OrgEventstore
UserEvents *usr_event.UserEventstore
ProjectEvents *proj_event.ProjectEventstore
}
type initializer struct {
*Setup
createdUsers map[string]*usr_model.User
createdOrgs map[string]*org_model.Org
createdProjects map[string]*proj_model.Project
}
const (
OrgOwnerRole = "ORG_OWNER"
SETUP_USER = "SETUP"
OIDCResponseType_CODE = "CODE"
OIDCResponseType_ID_TOKEN = "ID_TOKEN"
OIDCResponseType_TOKEN = "TOKEN"
OIDCGrantType_AUTHORIZATION_CODE = "AUTHORIZATION_CODE"
OIDCGrantType_IMPLICIT = "IMPLICIT"
OIDCGrantType_REFRESH_TOKEN = "REFRESH_TOKEN"
OIDCApplicationType_NATIVE = "NATIVE"
OIDCApplicationType_USER_AGENT = "USER_AGENT"
OIDCApplicationType_WEB = "WEB"
OIDCAuthMethodType_NONE = "NONE"
OIDCAuthMethodType_BASIC = "BASIC"
OIDCAuthMethodType_POST = "POST"
)
func StartSetup(sd systemdefaults.SystemDefaults, repos EventstoreRepos) *Setup {
return &Setup{
repos: repos,
iamID: sd.IamID,
setUpConfig: sd.SetUp,
}
}
func (s *Setup) Execute() error {
ctx := context.Background()
iam, err := s.repos.IamEvents.IamByID(ctx, s.iamID)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
if iam != nil && iam.SetUpDone {
return nil
}
if (iam != nil && !iam.SetUpStarted) || caos_errs.IsNotFound(err) {
ctx = setSetUpContextData(ctx, s.iamID)
iam, err = s.repos.IamEvents.StartSetup(ctx, s.iamID)
if err != nil {
return err
}
}
setUp := &initializer{
Setup: s,
createdUsers: make(map[string]*usr_model.User),
createdOrgs: make(map[string]*org_model.Org),
createdProjects: make(map[string]*proj_model.Project),
}
err = setUp.orgs(ctx, s.setUpConfig.Orgs)
if err != nil {
logging.Log("SETUP-p4oWq").WithError(err).Error("unable to set up orgs")
return err
}
ctx = setSetUpContextData(ctx, s.iamID)
err = setUp.iamOwners(ctx, s.setUpConfig.Owners)
if err != nil {
logging.Log("SETUP-WHr01").WithError(err).Error("unable to set up iam owners")
return err
}
err = setUp.setGlobalOrg(ctx)
if err != nil {
logging.Log("SETUP-0874m").WithError(err).Error("unable to set global org")
return err
}
err = setUp.setIamProject(ctx)
if err != nil {
logging.Log("SETUP-kaWjq").WithError(err).Error("unable to set citadel project")
return err
}
iam, err = s.repos.IamEvents.SetupDone(ctx, s.iamID)
if err != nil {
return err
}
return nil
}
func (setUp *initializer) orgs(ctx context.Context, orgs []types.Org) error {
for _, iamOrg := range orgs {
org, err := setUp.org(ctx, iamOrg)
if err != nil {
logging.LogWithFields("SETUP-IlLif", "Org", iamOrg.Name).WithError(err).Error("unable to create org")
return err
}
setUp.createdOrgs[iamOrg.Name] = org
ctx = setSetUpContextData(ctx, org.AggregateID)
err = setUp.users(ctx, iamOrg.Users)
if err != nil {
logging.LogWithFields("SETUP-8zfwz", "Org", iamOrg.Name).WithError(err).Error("unable to set up org users")
return err
}
err = setUp.orgOwners(ctx, org, iamOrg.Owners)
if err != nil {
logging.LogWithFields("SETUP-0874m", "Org", iamOrg.Name).WithError(err).Error("unable to set up org owners")
return err
}
err = setUp.projects(ctx, iamOrg.Projects)
if err != nil {
logging.LogWithFields("SETUP-wUzqY", "Org", iamOrg.Name).WithError(err).Error("unable to set up org projects")
return err
}
}
return nil
}
func (setUp *initializer) org(ctx context.Context, org types.Org) (*org_model.Org, error) {
ctx = setSetUpContextData(ctx, "")
createOrg := &org_model.Org{
Name: org.Name,
Domain: org.Domain,
}
return setUp.repos.OrgEvents.CreateOrg(ctx, createOrg)
}
func (setUp *initializer) iamOwners(ctx context.Context, owners []string) error {
for _, iamOwner := range owners {
user, ok := setUp.createdUsers[iamOwner]
if !ok {
logging.LogWithFields("SETUP-8siew", "Owner", iamOwner).Error("unable to add user to iam members")
return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-su6L3", "unable to add user to iam members")
}
_, err := setUp.repos.IamEvents.AddIamMember(ctx, &iam_model.IamMember{ObjectRoot: models.ObjectRoot{AggregateID: setUp.iamID}, UserID: user.AggregateID, Roles: []string{"IAM_OWNER"}})
if err != nil {
logging.Log("SETUP-LM7rI").WithError(err).Error("unable to add iam administrator to iam members as owner")
return err
}
}
return nil
}
func (setUp *initializer) setGlobalOrg(ctx context.Context) error {
globalOrg, ok := setUp.createdOrgs[setUp.setUpConfig.GlobalOrg]
if !ok {
logging.LogWithFields("SETUP-FBhs9", "GlobalOrg", setUp.setUpConfig.GlobalOrg).Error("global org not created")
return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-4GwU7", "global org not created: %v", setUp.setUpConfig.GlobalOrg)
}
_, err := setUp.repos.IamEvents.SetGlobalOrg(ctx, setUp.iamID, globalOrg.AggregateID)
logging.Log("SETUP-uGMA3").OnError(err).Error("unable to set global org on iam")
return err
}
func (setUp *initializer) setIamProject(ctx context.Context) error {
iamProject, ok := setUp.createdProjects[setUp.setUpConfig.IAMProject]
if !ok {
logging.LogWithFields("SETUP-SJFWP", "Iam Project", setUp.setUpConfig.IAMProject).Error("iam project created")
return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-sGmQt", "iam project not created: %v", setUp.setUpConfig.IAMProject)
}
_, err := setUp.repos.IamEvents.SetIamProject(ctx, setUp.iamID, iamProject.AggregateID)
logging.Log("SETUP-i1pNh").OnError(err).Error("unable to set iam project on iam")
return err
}
func (setUp *initializer) users(ctx context.Context, users []types.User) error {
for _, user := range users {
created, err := setUp.user(ctx, user)
if err != nil {
logging.LogWithFields("SETUP-9soer", "Email", user.Email).WithError(err).Error("unable to create iam user")
return err
}
setUp.createdUsers[user.Email] = created
}
return nil
}
func (setUp *initializer) user(ctx context.Context, user types.User) (*usr_model.User, error) {
createUser := &usr_model.User{
Profile: &usr_model.Profile{
UserName: user.UserName,
FirstName: user.FirstName,
LastName: user.LastName,
},
Email: &usr_model.Email{
EmailAddress: user.Email,
IsEmailVerified: true,
},
Password: &usr_model.Password{
SecretString: user.Password,
},
}
return setUp.repos.UserEvents.CreateUser(ctx, createUser)
}
func (setUp *initializer) orgOwners(ctx context.Context, org *org_model.Org, owners []string) error {
for _, orgOwner := range owners {
user, ok := setUp.createdUsers[orgOwner]
if !ok {
logging.LogWithFields("SETUP-s9ilr", "Owner", orgOwner).Error("unable to add user to org members")
return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-s0prs", "unable to add user to org members: %v", orgOwner)
}
err := setUp.orgOwner(ctx, org, user)
if err != nil {
logging.Log("SETUP-s90oe").WithError(err).Error("unable to add global org admin to members of global org")
return err
}
}
return nil
}
func (setUp *initializer) orgOwner(ctx context.Context, org *org_model.Org, user *usr_model.User) error {
addMember := &org_model.OrgMember{
ObjectRoot: models.ObjectRoot{AggregateID: org.AggregateID},
UserID: user.AggregateID,
Roles: []string{OrgOwnerRole},
}
_, err := setUp.repos.OrgEvents.AddOrgMember(ctx, addMember)
return err
}
func (setUp *initializer) projects(ctx context.Context, projects []types.Project) error {
for _, project := range projects {
createdProject, err := setUp.project(ctx, project)
if err != nil {
return err
}
setUp.createdProjects[createdProject.Name] = createdProject
for _, oidc := range project.OIDCApps {
_, err := setUp.oidcApp(ctx, createdProject, oidc)
if err != nil {
return err
}
}
}
return nil
}
func (setUp *initializer) project(ctx context.Context, project types.Project) (*proj_model.Project, error) {
addProject := &proj_model.Project{
Name: project.Name,
}
return setUp.repos.ProjectEvents.CreateProject(ctx, addProject)
}
func (setUp *initializer) oidcApp(ctx context.Context, project *proj_model.Project, oidc types.OIDCApp) (*proj_model.Application, error) {
addOIDCApp := &proj_model.Application{
ObjectRoot: models.ObjectRoot{AggregateID: project.AggregateID},
Name: oidc.Name,
OIDCConfig: &proj_model.OIDCConfig{
RedirectUris: oidc.RedirectUris,
ResponseTypes: getOIDCResponseTypes(oidc.ResponseTypes),
GrantTypes: getOIDCGrantTypes(oidc.GrantTypes),
ApplicationType: getOIDCApplicationType(oidc.ApplicationType),
AuthMethodType: getOIDCAuthMethod(oidc.AuthMethodType),
PostLogoutRedirectUris: oidc.PostLogoutRedirectUris,
},
}
return setUp.repos.ProjectEvents.AddApplication(ctx, addOIDCApp)
}
func getOIDCResponseTypes(responseTypes []string) []proj_model.OIDCResponseType {
types := make([]proj_model.OIDCResponseType, len(responseTypes))
for i, t := range responseTypes {
types[i] = getOIDCResponseType(t)
}
return types
}
func getOIDCResponseType(responseType string) proj_model.OIDCResponseType {
switch responseType {
case OIDCResponseType_CODE:
return proj_model.OIDCRESPONSETYPE_CODE
case OIDCResponseType_ID_TOKEN:
return proj_model.OIDCRESPONSETYPE_ID_TOKEN
case OIDCResponseType_TOKEN:
return proj_model.OIDCRESPONSETYPE_TOKEN
}
return proj_model.OIDCRESPONSETYPE_CODE
}
func getOIDCGrantTypes(grantTypes []string) []proj_model.OIDCGrantType {
types := make([]proj_model.OIDCGrantType, len(grantTypes))
for i, t := range grantTypes {
types[i] = getOIDCGrantType(t)
}
return types
}
func getOIDCGrantType(grantTypes string) proj_model.OIDCGrantType {
switch grantTypes {
case OIDCGrantType_AUTHORIZATION_CODE:
return proj_model.OIDCGRANTTYPE_AUTHORIZATION_CODE
case OIDCGrantType_IMPLICIT:
return proj_model.OIDCGRANTTYPE_IMPLICIT
case OIDCGrantType_REFRESH_TOKEN:
return proj_model.OIDCGRANTTYPE_REFRESH_TOKEN
}
return proj_model.OIDCGRANTTYPE_AUTHORIZATION_CODE
}
func getOIDCApplicationType(appType string) proj_model.OIDCApplicationType {
switch appType {
case OIDCApplicationType_NATIVE:
return proj_model.OIDCAPPLICATIONTYPE_NATIVE
case OIDCApplicationType_USER_AGENT:
return proj_model.OIDCAPPLICATIONTYPE_USER_AGENT
case OIDCApplicationType_WEB:
return proj_model.OIDCAPPLICATIONTYPE_WEB
}
return proj_model.OIDCAPPLICATIONTYPE_WEB
}
func getOIDCAuthMethod(authMethod string) proj_model.OIDCAuthMethodType {
switch authMethod {
case OIDCAuthMethodType_NONE:
return proj_model.OIDCAUTHMETHODTYPE_NONE
case OIDCAuthMethodType_BASIC:
return proj_model.OIDCAUTHMETHODTYPE_BASIC
case OIDCAuthMethodType_POST:
return proj_model.OIDCAUTHMETHODTYPE_POST
}
return proj_model.OIDCAUTHMETHODTYPE_NONE
}
func setSetUpContextData(ctx context.Context, orgID string) context.Context {
return auth.SetCtxData(ctx, auth.CtxData{UserID: SETUP_USER, OrgID: orgID})
}

View File

@ -59,6 +59,10 @@ func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t Toke
return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID}), nil
}
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {
return context.WithValue(ctx, dataKey, ctxData)
}
func GetCtxData(ctx context.Context) CtxData {
ctxData, _ := ctx.Value(dataKey).(CtxData)
return ctxData

View File

@ -1,6 +1,7 @@
package systemdefaults
import (
"github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/crypto"
pol "github.com/caos/zitadel/internal/policy"
)
@ -10,6 +11,8 @@ type SystemDefaults struct {
UserVerificationKey *crypto.KeyConfig
Multifactors MultifactorConfig
DefaultPolicies DefaultPolicies
IamID string
SetUp types.IAMSetUp
}
type SecretGenerators struct {

View File

@ -0,0 +1,41 @@
package types
type IAMSetUp struct {
GlobalOrg string
IAMProject string
Orgs []Org
Owners []string
}
type User struct {
FirstName string
LastName string
UserName string
Email string
Password string
}
type Org struct {
Name string
Domain string
Users []User
Owners []string
Projects []Project
}
type Project struct {
Name string
Users []User
Members []string
OIDCApps []OIDCApp
}
type OIDCApp struct {
Name string
RedirectUris []string
ResponseTypes []string
GrantTypes []string
ApplicationType string
AuthMethodType string
PostLogoutRedirectUris []string
}

23
internal/iam/model/iam.go Normal file
View File

@ -0,0 +1,23 @@
package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type Iam struct {
es_models.ObjectRoot
GlobalOrgID string
IamProjectID string
SetUpDone bool
SetUpStarted bool
Members []*IamMember
}
func (iam *Iam) GetMember(userID string) (int, *IamMember) {
for i, m := range iam.Members {
if m.UserID == userID {
return i, m
}
}
return -1, nil
}

View File

@ -0,0 +1,18 @@
package model
import es_models "github.com/caos/zitadel/internal/eventstore/models"
type IamMember struct {
es_models.ObjectRoot
UserID string
Roles []string
}
func NewIamMember(projectID, userID string) *IamMember {
return &IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, UserID: userID}
}
func (i *IamMember) IsValid() bool {
return i.AggregateID != "" && i.UserID != "" && len(i.Roles) != 0
}

View File

@ -0,0 +1,35 @@
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/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

@ -0,0 +1,190 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/cache/config"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
caos_errs "github.com/caos/zitadel/internal/errors"
es_int "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
)
type IamEventstore struct {
es_int.Eventstore
iamCache *IamCache
}
type IamConfig struct {
es_int.Eventstore
Cache *config.CacheConfig
}
func StartIam(conf IamConfig, systemDefaults sd.SystemDefaults) (*IamEventstore, error) {
iamCache, err := StartCache(conf.Cache)
if err != nil {
return nil, err
}
return &IamEventstore{
Eventstore: conf.Eventstore,
iamCache: iamCache,
}, nil
}
func (es *IamEventstore) IamByID(ctx context.Context, id string) (*iam_model.Iam, error) {
iam := es.iamCache.getIam(id)
query, err := IamByIDQuery(iam.AggregateID, iam.Sequence)
if err != nil {
return nil, err
}
err = es_sdk.Filter(ctx, es.FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
es.iamCache.cacheIam(iam)
return model.IamToModel(iam), nil
}
func (es *IamEventstore) StartSetup(ctx context.Context, iamID string) (*iam_model.Iam, error) {
iam, err := es.IamByID(ctx, iamID)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if iam != nil && iam.SetUpStarted {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "Setup already started")
}
repoIam := &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: iamID}}
createAggregate := IamSetupStartedAggregate(es.AggregateCreator(), repoIam)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, createAggregate)
if err != nil {
return nil, err
}
es.iamCache.cacheIam(repoIam)
return model.IamToModel(repoIam), nil
}
func (es *IamEventstore) SetupDone(ctx context.Context, iamID string) (*iam_model.Iam, error) {
iam, err := es.IamByID(ctx, iamID)
if err != nil {
return nil, err
}
repoIam := model.IamFromModel(iam)
createAggregate := IamSetupDoneAggregate(es.AggregateCreator(), repoIam)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, createAggregate)
if err != nil {
return nil, err
}
es.iamCache.cacheIam(repoIam)
return model.IamToModel(repoIam), nil
}
func (es *IamEventstore) SetGlobalOrg(ctx context.Context, iamID, globalOrg string) (*iam_model.Iam, error) {
iam, err := es.IamByID(ctx, iamID)
if err != nil {
return nil, err
}
repoIam := model.IamFromModel(iam)
createAggregate := IamSetGlobalOrgAggregate(es.AggregateCreator(), repoIam, globalOrg)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, createAggregate)
if err != nil {
return nil, err
}
es.iamCache.cacheIam(repoIam)
return model.IamToModel(repoIam), nil
}
func (es *IamEventstore) SetIamProject(ctx context.Context, iamID, iamProjectID string) (*iam_model.Iam, error) {
iam, err := es.IamByID(ctx, iamID)
if err != nil {
return nil, err
}
repoIam := model.IamFromModel(iam)
createAggregate := IamSetIamProjectAggregate(es.AggregateCreator(), repoIam, iamProjectID)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, createAggregate)
if err != nil {
return nil, err
}
es.iamCache.cacheIam(repoIam)
return model.IamToModel(repoIam), nil
}
func (es *IamEventstore) AddIamMember(ctx context.Context, member *iam_model.IamMember) (*iam_model.IamMember, error) {
if !member.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-89osr", "UserID and Roles are required")
}
existing, err := es.IamByID(ctx, member.AggregateID)
if err != nil {
return nil, err
}
if _, m := existing.GetMember(member.UserID); m != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "EVENT-idke6", "User is already member of this Iam")
}
repoIam := model.IamFromModel(existing)
repoMember := model.IamMemberFromModel(member)
addAggregate := IamMemberAddedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, addAggregate)
if err != nil {
return nil, err
}
es.iamCache.cacheIam(repoIam)
if _, m := model.GetIamMember(repoIam.Members, member.UserID); m != nil {
return model.IamMemberToModel(m), nil
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-s90pw", "Could not find member in list")
}
func (es *IamEventstore) ChangeIamMember(ctx context.Context, member *iam_model.IamMember) (*iam_model.IamMember, error) {
if !member.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-s9ipe", "UserID and Roles are required")
}
existing, err := es.IamByID(ctx, member.AggregateID)
if err != nil {
return nil, err
}
if _, m := existing.GetMember(member.UserID); m == nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-s7ucs", "User is not member of this project")
}
repoIam := model.IamFromModel(existing)
repoMember := model.IamMemberFromModel(member)
projectAggregate := IamMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, projectAggregate)
es.iamCache.cacheIam(repoIam)
if _, m := model.GetIamMember(repoIam.Members, member.UserID); m != nil {
return model.IamMemberToModel(m), nil
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-29cws", "Could not find member in list")
}
func (es *IamEventstore) RemoveIamMember(ctx context.Context, member *iam_model.IamMember) error {
if member.UserID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-0pors", "UserID and Roles are required")
}
existing, err := es.IamByID(ctx, member.AggregateID)
if err != nil {
return err
}
if _, m := existing.GetMember(member.UserID); m == nil {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-29skr", "User is not member of this project")
}
repoIam := model.IamFromModel(existing)
repoMember := model.IamMemberFromModel(member)
projectAggregate := IamMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, projectAggregate)
es.iamCache.cacheIam(repoIam)
return err
}

View File

@ -0,0 +1,74 @@
package eventsourcing
import (
"encoding/json"
mock_cache "github.com/caos/zitadel/internal/cache/mock"
"github.com/caos/zitadel/internal/eventstore/mock"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/golang/mock/gomock"
)
func GetMockedEventstore(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *IamEventstore {
return &IamEventstore{
Eventstore: mockEs,
iamCache: GetMockCache(ctrl),
}
}
func GetMockCache(ctrl *gomock.Controller) *IamCache {
mockCache := mock_cache.NewMockCache(ctrl)
mockCache.EXPECT().Get(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
mockCache.EXPECT().Set(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
return &IamCache{iamCache: mockCache}
}
func GetMockIamByIDOK(ctrl *gomock.Controller) *IamEventstore {
data, _ := json.Marshal(model.Iam{GlobalOrgID: "GlobalOrgID"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.IamSetupStarted},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.GlobalOrgSet, Data: data},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockIamByIDNoEvents(ctrl *gomock.Controller) *IamEventstore {
events := []*es_models.Event{}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateIam(ctrl *gomock.Controller) *IamEventstore {
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.IamSetupStarted},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateIamWithMember(ctrl *gomock.Controller) *IamEventstore {
memberData, _ := json.Marshal(model.IamMember{UserID: "UserID", Roles: []string{"Role"}})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.IamSetupStarted},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.IamMemberAdded, Data: memberData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateIamNotExisting(ctrl *gomock.Controller) *IamEventstore {
events := []*es_models.Event{}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}

View File

@ -0,0 +1,637 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/api/auth"
caos_errs "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/golang/mock/gomock"
"testing"
)
func TestIamByID(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
iam *model.Iam
}
type res struct {
iam *model.Iam
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "iam from events, ok",
args: args{
es: GetMockIamByIDOK(ctrl),
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
},
res: res{
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
},
},
{
name: "iam from events, no events",
args: args{
es: GetMockIamByIDNoEvents(ctrl),
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
{
name: "iam from events, no id",
args: args{
es: GetMockIamByIDNoEvents(ctrl),
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "", Sequence: 1}},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.IamByID(nil, tt.args.iam.AggregateID)
if tt.res.errFunc == nil && result.AggregateID != tt.res.iam.AggregateID {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.iam.AggregateID, result.AggregateID)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestSetUpStarted(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
iamID string
}
type res struct {
iam *model.Iam
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "setup started iam, ok",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
},
res: res{
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true},
},
},
{
name: "setup already started",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "setup iam no id",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.StartSetup(tt.args.ctx, tt.args.iamID)
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
}
if tt.res.errFunc == nil && result.SetUpStarted != tt.res.iam.SetUpStarted {
t.Errorf("got wrong result setupStarted: expected: %v, actual: %v ", tt.res.iam.SetUpStarted, result.SetUpStarted)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestSetUpDone(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
iamID string
}
type res struct {
iam *model.Iam
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "setup done iam, ok",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
},
res: res{
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true, SetUpDone: true},
},
},
{
name: "setup iam no id",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "iam not found",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.SetupDone(tt.args.ctx, tt.args.iamID)
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
}
if tt.res.errFunc == nil && result.SetUpDone != tt.res.iam.SetUpDone {
t.Errorf("got wrong result SetUpDone: expected: %v, actual: %v ", tt.res.iam.SetUpDone, result.SetUpDone)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestSetGlobalOrg(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
iamID string
globalOrg string
}
type res struct {
iam *model.Iam
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "global org set, ok",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
globalOrg: "globalOrg",
},
res: res{
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true, GlobalOrgID: "globalOrg"},
},
},
{
name: "no iam id",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
globalOrg: "",
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "no global org",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "iam not found",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
globalOrg: "globalOrg",
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.SetGlobalOrg(tt.args.ctx, tt.args.iamID, tt.args.globalOrg)
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
}
if tt.res.errFunc == nil && result.GlobalOrgID != tt.res.iam.GlobalOrgID {
t.Errorf("got wrong result GlobalOrgID: expected: %v, actual: %v ", tt.res.iam.GlobalOrgID, result.GlobalOrgID)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestSetIamProjectID(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
iamID string
iamProjectID string
}
type res struct {
iam *model.Iam
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "iam project set, ok",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
iamProjectID: "iamProjectID",
},
res: res{
iam: &model.Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true, IamProjectID: "iamProjectID"},
},
},
{
name: "no iam id",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamProjectID: "",
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "no global org",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "iam not found",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
iamID: "iamID",
iamProjectID: "iamProjectID",
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.SetIamProject(tt.args.ctx, tt.args.iamID, tt.args.iamProjectID)
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
}
if tt.res.errFunc == nil && result.IamProjectID != tt.res.iam.IamProjectID {
t.Errorf("got wrong result IamProjectID: expected: %v, actual: %v ", tt.res.iam.IamProjectID, result.IamProjectID)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestAddIamMember(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
member *iam_model.IamMember
}
type res struct {
result *iam_model.IamMember
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add iam member, ok",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
res: res{
result: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
},
{
name: "no userid",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Roles: []string{"Roles"}},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "no roles",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID"},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "member already existing",
args: args{
es: GetMockManipulateIamWithMember(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
res: res{
errFunc: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.AddIamMember(tt.args.ctx, tt.args.member)
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
}
if tt.res.errFunc == nil && result.UserID != tt.res.result.UserID {
t.Errorf("got wrong result userid: expected: %v, actual: %v ", tt.res.result.UserID, result.UserID)
}
if tt.res.errFunc == nil && len(result.Roles) != len(tt.res.result.Roles) {
t.Errorf("got wrong result roles: expected: %v, actual: %v ", tt.res.result.Roles, result.Roles)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestChangeIamMember(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
member *iam_model.IamMember
}
type res struct {
result *iam_model.IamMember
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add iam member, ok",
args: args{
es: GetMockManipulateIamWithMember(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"ChangeRoles"}},
},
res: res{
result: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
},
{
name: "no userid",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Roles: []string{"ChangeRoles"}},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "no roles",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID"},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "member not existing",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing not found",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"ChangeRoles"}},
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.ChangeIamMember(tt.args.ctx, tt.args.member)
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
}
if tt.res.errFunc == nil && result.UserID != tt.res.result.UserID {
t.Errorf("got wrong result userid: expected: %v, actual: %v ", tt.res.result.UserID, result.UserID)
}
if tt.res.errFunc == nil && len(result.Roles) != len(tt.res.result.Roles) {
t.Errorf("got wrong result roles: expected: %v, actual: %v ", tt.res.result.Roles, result.Roles)
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestRemoveIamMember(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IamEventstore
ctx context.Context
existing *model.Iam
member *iam_model.IamMember
}
type res struct {
result *iam_model.IamMember
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove iam member, ok",
args: args{
es: GetMockManipulateIamWithMember(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{
ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
Members: []*model.IamMember{&model.IamMember{UserID: "UserID", Roles: []string{"Roles"}}},
},
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID"},
},
res: res{
result: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
},
{
name: "no userid",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{
ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
Members: []*model.IamMember{&model.IamMember{UserID: "UserID", Roles: []string{"Roles"}}},
},
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Roles: []string{"ChangeRoles"}},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "member not existing",
args: args{
es: GetMockManipulateIam(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{
ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
},
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing not found",
args: args{
es: GetMockManipulateIamNotExisting(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
member: &iam_model.IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", Roles: []string{"ChangeRoles"}},
},
res: res{
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.RemoveIamMember(tt.args.ctx, tt.args.member)
if tt.res.errFunc == nil && err != nil {
t.Errorf("should not get err")
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}

View File

@ -0,0 +1,124 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/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", "id should be filled")
}
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", "existing iam should not be nil")
}
return aggCreator.NewAggregate(ctx, iam.AggregateID, model.IamAggregate, model.IamVersion, iam.Sequence)
}
func IamAggregateOverwriteContext(ctx context.Context, aggCreator *es_models.AggregateCreator, iam *model.Iam, resourceOwnerID string, userID string) (*es_models.Aggregate, error) {
if iam == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dis83", "existing iam should not be nil")
}
return aggCreator.NewAggregate(ctx, iam.AggregateID, model.IamAggregate, model.IamVersion, iam.Sequence, es_models.OverwriteResourceOwner(resourceOwnerID), es_models.OverwriteEditorUser(userID))
}
func IamSetupStartedAggregate(aggCreator *es_models.AggregateCreator, iam *model.Iam) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
agg, err := IamAggregate(ctx, aggCreator, iam)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.IamSetupStarted, nil)
}
}
func IamSetupDoneAggregate(aggCreator *es_models.AggregateCreator, iam *model.Iam) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
agg, err := IamAggregate(ctx, aggCreator, iam)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.IamSetupDone, nil)
}
}
func IamSetGlobalOrgAggregate(aggCreator *es_models.AggregateCreator, iam *model.Iam, globalOrg string) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if globalOrg == "" {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-8siwa", "globalOrg must be set")
}
agg, err := IamAggregate(ctx, aggCreator, iam)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.GlobalOrgSet, &model.Iam{GlobalOrgID: globalOrg})
}
}
func IamSetIamProjectAggregate(aggCreator *es_models.AggregateCreator, iam *model.Iam, projectID string) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if projectID == "" {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sjuw3", "projectID must be set")
}
agg, err := IamAggregate(ctx, aggCreator, iam)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.IamProjectSet, &model.Iam{IamProjectID: projectID})
}
}
func IamMemberAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Iam, member *model.IamMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9sope", "member should not be nil")
}
agg, err := IamAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.IamMemberAdded, member)
}
}
func IamMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Iam, member *model.IamMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-38skf", "member should not be nil")
}
agg, err := IamAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.IamMemberChanged, member)
}
}
func IamMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Iam, member *model.IamMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-90lsw", "member should not be nil")
}
agg, err := IamAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.IamMemberRemoved, member)
}
}

View File

@ -0,0 +1,510 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/api/auth"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"testing"
)
func TestSetUpStartedAggregate(t *testing.T) {
type args struct {
ctx context.Context
iam *model.Iam
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "setupstarted aggregate ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
iam: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamSetupStarted,
},
},
{
name: "iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
iam: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamSetupStarted,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamSetupStartedAggregate(tt.args.aggCreator, tt.args.iam)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestSetUpDoneAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Iam
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "setup done aggregate ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamSetupDone,
},
},
{
name: "existing iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamSetupDone,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamSetupDoneAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestGlobalOrgAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Iam
orgID string
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "global org set aggregate ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
orgID: "orgID",
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.GlobalOrgSet,
},
},
{
name: "existing iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: nil,
orgID: "orgID",
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "global org empty",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamSetGlobalOrgAggregate(tt.args.aggCreator, tt.args.existing, tt.args.orgID)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestIamProjectAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Iam
projectID string
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "iam project id set aggregate ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
projectID: "projectID",
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamProjectSet,
},
},
{
name: "existing iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: nil,
projectID: "projectID",
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "project id empty",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamSetIamProjectAggregate(tt.args.aggCreator, tt.args.existing, tt.args.projectID)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestIamMemberAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Iam
new *model.IamMember
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "iammember added ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: &model.IamMember{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, UserID: "UserID", Roles: []string{"Roles"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberAdded,
},
},
{
name: "existing iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberAdded,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "member nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberAdded,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamMemberAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if tt.res.errFunc == nil && agg.Events[0].Data == nil {
t.Errorf("should have data in event")
}
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestIamMemberChangedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Iam
new *model.IamMember
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "iammember changed ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: &model.IamMember{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, UserID: "UserID", Roles: []string{"Roles"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberChanged,
},
},
{
name: "existing iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberChanged,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "member nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberChanged,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamMemberChangedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if !tt.res.wantErr && agg.Events[0].Data == nil {
t.Errorf("should have data in event")
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestIamMemberRemovedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Iam
new *model.IamMember
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "iammember removed ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: &model.IamMember{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, UserID: "UserID", Roles: []string{"Roles"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberRemoved,
},
},
{
name: "existing iam nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberRemoved,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "member nil",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Iam{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.IamMemberRemoved,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := IamMemberRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if !tt.res.wantErr && agg.Events[0].Data == nil {
t.Errorf("should have data in event")
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}

View File

@ -0,0 +1,86 @@
package model
import (
"encoding/json"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/model"
)
const (
IamVersion = "v1"
)
type Iam struct {
es_models.ObjectRoot
SetUpStarted bool `json:"-"`
SetUpDone bool `json:"-"`
GlobalOrgID string `json:"globalOrgId,omitempty"`
IamProjectID string `json:"iamProjectId,omitempty"`
Members []*IamMember `json:"-"`
}
func IamFromModel(iam *model.Iam) *Iam {
members := IamMembersFromModel(iam.Members)
converted := &Iam{
ObjectRoot: iam.ObjectRoot,
SetUpStarted: iam.SetUpStarted,
SetUpDone: iam.SetUpDone,
GlobalOrgID: iam.GlobalOrgID,
IamProjectID: iam.IamProjectID,
Members: members,
}
return converted
}
func IamToModel(iam *Iam) *model.Iam {
members := IamMembersToModel(iam.Members)
converted := &model.Iam{
ObjectRoot: iam.ObjectRoot,
SetUpStarted: iam.SetUpStarted,
SetUpDone: iam.SetUpDone,
GlobalOrgID: iam.GlobalOrgID,
IamProjectID: iam.IamProjectID,
Members: members,
}
return converted
}
func (i *Iam) AppendEvents(events ...*es_models.Event) error {
for _, event := range events {
if err := i.AppendEvent(event); err != nil {
return err
}
}
return nil
}
func (i *Iam) AppendEvent(event *es_models.Event) (err error) {
i.ObjectRoot.AppendEvent(event)
switch event.Type {
case IamSetupStarted:
i.SetUpStarted = true
case IamSetupDone:
i.SetUpDone = true
case IamProjectSet,
GlobalOrgSet:
err = i.setData(event)
case IamMemberAdded:
err = i.appendAddMemberEvent(event)
case IamMemberChanged:
err = i.appendChangeMemberEvent(event)
case IamMemberRemoved:
err = i.appendRemoveMemberEvent(event)
}
return err
}
func (i *Iam) setData(event *es_models.Event) error {
i.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, i); err != nil {
logging.Log("EVEN-9sie4").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-slwi3", "could not unmarshal event")
}
return nil
}

View File

@ -0,0 +1,101 @@
package model
import (
"encoding/json"
"github.com/caos/logging"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/model"
)
type IamMember struct {
es_models.ObjectRoot
UserID string `json:"userId,omitempty"`
Roles []string `json:"roles,omitempty"`
}
func GetIamMember(members []*IamMember, id string) (int, *IamMember) {
for i, m := range members {
if m.UserID == id {
return i, m
}
}
return -1, nil
}
func IamMembersToModel(members []*IamMember) []*model.IamMember {
convertedMembers := make([]*model.IamMember, len(members))
for i, m := range members {
convertedMembers[i] = IamMemberToModel(m)
}
return convertedMembers
}
func IamMembersFromModel(members []*model.IamMember) []*IamMember {
convertedMembers := make([]*IamMember, len(members))
for i, m := range members {
convertedMembers[i] = IamMemberFromModel(m)
}
return convertedMembers
}
func IamMemberFromModel(member *model.IamMember) *IamMember {
return &IamMember{
ObjectRoot: member.ObjectRoot,
UserID: member.UserID,
Roles: member.Roles,
}
}
func IamMemberToModel(member *IamMember) *model.IamMember {
return &model.IamMember{
ObjectRoot: member.ObjectRoot,
UserID: member.UserID,
Roles: member.Roles,
}
}
func (iam *Iam) appendAddMemberEvent(event *es_models.Event) error {
member := &IamMember{}
err := member.setData(event)
if err != nil {
return err
}
member.ObjectRoot.CreationDate = event.CreationDate
iam.Members = append(iam.Members, member)
return nil
}
func (iam *Iam) appendChangeMemberEvent(event *es_models.Event) error {
member := &IamMember{}
err := member.setData(event)
if err != nil {
return err
}
if i, m := GetIamMember(iam.Members, member.UserID); m != nil {
iam.Members[i] = member
}
return nil
}
func (iam *Iam) appendRemoveMemberEvent(event *es_models.Event) error {
member := &IamMember{}
err := member.setData(event)
if err != nil {
return err
}
if i, m := GetIamMember(iam.Members, member.UserID); m != nil {
iam.Members[i] = iam.Members[len(iam.Members)-1]
iam.Members[len(iam.Members)-1] = nil
iam.Members = iam.Members[:len(iam.Members)-1]
}
return nil
}
func (m *IamMember) setData(event *es_models.Event) error {
m.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, m); err != nil {
logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data")
return err
}
return nil
}

View File

@ -0,0 +1,118 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"testing"
)
func TestAppendAddMemberEvent(t *testing.T) {
type args struct {
iam *Iam
member *IamMember
event *es_models.Event
}
tests := []struct {
name string
args args
result *Iam
}{
{
name: "append add member event",
args: args{
iam: &Iam{},
member: &IamMember{UserID: "UserID", Roles: []string{"Role"}},
event: &es_models.Event{},
},
result: &Iam{Members: []*IamMember{&IamMember{UserID: "UserID", Roles: []string{"Role"}}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.member != nil {
data, _ := json.Marshal(tt.args.member)
tt.args.event.Data = data
}
tt.args.iam.appendAddMemberEvent(tt.args.event)
if len(tt.args.iam.Members) != 1 {
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.iam.Members))
}
if tt.args.iam.Members[0] == tt.result.Members[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Members[0], tt.args.iam.Members[0])
}
})
}
}
func TestAppendChangeMemberEvent(t *testing.T) {
type args struct {
iam *Iam
member *IamMember
event *es_models.Event
}
tests := []struct {
name string
args args
result *Iam
}{
{
name: "append change member event",
args: args{
iam: &Iam{Members: []*IamMember{&IamMember{UserID: "UserID", Roles: []string{"Role"}}}},
member: &IamMember{UserID: "UserID", Roles: []string{"ChangedRole"}},
event: &es_models.Event{},
},
result: &Iam{Members: []*IamMember{&IamMember{UserID: "UserID", Roles: []string{"ChangedRole"}}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.member != nil {
data, _ := json.Marshal(tt.args.member)
tt.args.event.Data = data
}
tt.args.iam.appendChangeMemberEvent(tt.args.event)
if len(tt.args.iam.Members) != 1 {
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.iam.Members))
}
if tt.args.iam.Members[0] == tt.result.Members[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Members[0], tt.args.iam.Members[0])
}
})
}
}
func TestAppendRemoveMemberEvent(t *testing.T) {
type args struct {
iam *Iam
member *IamMember
event *es_models.Event
}
tests := []struct {
name string
args args
result *Iam
}{
{
name: "append remove member event",
args: args{
iam: &Iam{Members: []*IamMember{&IamMember{UserID: "UserID", Roles: []string{"Role"}}}},
member: &IamMember{UserID: "UserID"},
event: &es_models.Event{},
},
result: &Iam{Members: []*IamMember{}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.member != nil {
data, _ := json.Marshal(tt.args.member)
tt.args.event.Data = data
}
tt.args.iam.appendRemoveMemberEvent(tt.args.event)
if len(tt.args.iam.Members) != 0 {
t.Errorf("got wrong result should have no member actual: %v ", len(tt.args.iam.Members))
}
})
}
}

View File

@ -0,0 +1,74 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"testing"
)
func mockIamData(iam *Iam) []byte {
data, _ := json.Marshal(iam)
return data
}
func TestProjectRoleAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
iam *Iam
}
tests := []struct {
name string
args args
result *Iam
}{
{
name: "append set up start event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: IamSetupStarted, ResourceOwner: "OrgID"},
iam: &Iam{},
},
result: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
},
{
name: "append set up done event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: IamSetupDone, ResourceOwner: "OrgID"},
iam: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
},
result: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true, SetUpDone: true},
},
{
name: "append globalorg event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: GlobalOrgSet, ResourceOwner: "OrgID", Data: mockIamData(&Iam{GlobalOrgID: "GlobalOrg"})},
iam: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
},
result: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true, GlobalOrgID: "GlobalOrg"},
},
{
name: "append iamproject event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: IamProjectSet, ResourceOwner: "OrgID", Data: mockIamData(&Iam{IamProjectID: "IamProject"})},
iam: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
},
result: &Iam{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true, IamProjectID: "IamProject"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.iam.AppendEvent(tt.args.event)
if tt.args.iam.AggregateID != tt.result.AggregateID {
t.Errorf("got wrong result AggregateID: expected: %v, actual: %v ", tt.result.AggregateID, tt.args.iam.AggregateID)
}
if tt.args.iam.SetUpDone != tt.result.SetUpDone {
t.Errorf("got wrong result SetUpDone: expected: %v, actual: %v ", tt.result.SetUpDone, tt.args.iam.SetUpDone)
}
if tt.args.iam.GlobalOrgID != tt.result.GlobalOrgID {
t.Errorf("got wrong result GlobalOrgID: expected: %v, actual: %v ", tt.result.GlobalOrgID, tt.args.iam.GlobalOrgID)
}
if tt.args.iam.IamProjectID != tt.result.IamProjectID {
t.Errorf("got wrong result IamProjectID: expected: %v, actual: %v ", tt.result.IamProjectID, tt.args.iam.IamProjectID)
}
})
}
}

View File

@ -0,0 +1,15 @@
package model
import "github.com/caos/zitadel/internal/eventstore/models"
const (
IamAggregate models.AggregateType = "iam"
IamSetupStarted models.EventType = "iam.setup.started"
IamSetupDone models.EventType = "iam.setup.done"
GlobalOrgSet models.EventType = "iam.global.org.set"
IamProjectSet models.EventType = "iam.project.iam.set"
IamMemberAdded models.EventType = "iam.member.added"
IamMemberChanged models.EventType = "iam.member.changed"
IamMemberRemoved models.EventType = "iam.member.removed"
)

View File

@ -0,0 +1,30 @@
package eventstore
import (
"context"
org_model "github.com/caos/zitadel/internal/org/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
)
type OrgMemberRepository struct {
*org_es.OrgEventstore
}
func (repo *OrgMemberRepository) OrgMemberByID(ctx context.Context, orgID, userID string) (member *org_model.OrgMember, err error) {
member = org_model.NewOrgMember(orgID, userID)
return repo.OrgEventstore.OrgMemberByIDs(ctx, member)
}
func (repo *OrgMemberRepository) AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
return repo.OrgEventstore.AddOrgMember(ctx, member)
}
func (repo *OrgMemberRepository) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
return repo.OrgEventstore.ChangeOrgMember(ctx, member)
}
func (repo *OrgMemberRepository) RemoveOrgMember(ctx context.Context, orgID, userID string) error {
member := org_model.NewOrgMember(orgID, userID)
return repo.OrgEventstore.RemoveOrgMember(ctx, member)
}

View File

@ -41,3 +41,4 @@ func (o *Org) ContainsMember(userID string) bool {
}
return false
}

View File

@ -50,12 +50,12 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie7", "org should not be nil")
}
domainAgrregate, err := uniqueDomainAggregate(ctx, aggCreator, org.Domain)
domainAgrregate, err := uniqueDomainAggregate(ctx, aggCreator, org.AggregateID, org.Domain)
if err != nil {
return nil, err
}
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, org.Name)
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, org.AggregateID, org.Name)
if err != nil {
return nil, err
}
@ -91,7 +91,7 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre
aggregates := make([]*es_models.Aggregate, 0, 3)
if name, ok := changes["name"]; ok {
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, name.(string))
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, "", name.(string))
if err != nil {
return nil, err
}
@ -99,7 +99,7 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre
}
if name, ok := changes["domain"]; ok {
domainAggregate, err := uniqueDomainAggregate(ctx, aggCreator, name.(string))
domainAggregate, err := uniqueDomainAggregate(ctx, aggCreator, "", name.(string))
if err != nil {
return nil, err
}
@ -154,8 +154,11 @@ func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) fu
}
}
func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, domain string) (*es_models.Aggregate, error) {
func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
aggregate, err := aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0)
if resourceOwner != "" {
aggregate, err = aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
}
if err != nil {
return nil, err
}
@ -167,8 +170,11 @@ func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateC
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, org_model.OrgDomainReserved)), nil
}
func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, name string) (*es_models.Aggregate, error) {
aggregate, err := aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0)
func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
aggregate, err = aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0)
if resourceOwner != "" {
aggregate, err = aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
}
if err != nil {
return nil, err
}

View File

@ -141,7 +141,7 @@ func Test_uniqueNameAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := uniqueNameAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.orgName)
got, err := uniqueNameAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgName)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
@ -197,7 +197,7 @@ func Test_uniqueDomainAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := uniqueDomainAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.orgDomain)
got, err := uniqueDomainAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgDomain)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,6 @@ import (
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes/empty"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
@ -24,13 +23,11 @@ import (
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
func request_AdminService_Healthz_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
@ -41,15 +38,6 @@ func request_AdminService_Healthz_0(ctx context.Context, marshaler runtime.Marsh
}
func local_request_AdminService_Healthz_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := server.Healthz(ctx, &protoReq)
return msg, metadata, err
}
func request_AdminService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
@ -59,15 +47,6 @@ func request_AdminService_Ready_0(ctx context.Context, marshaler runtime.Marshal
}
func local_request_AdminService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := server.Ready(ctx, &protoReq)
return msg, metadata, err
}
func request_AdminService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
@ -77,15 +56,6 @@ func request_AdminService_Validate_0(ctx context.Context, marshaler runtime.Mars
}
func local_request_AdminService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := server.Validate(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_AdminService_IsOrgUnique_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
@ -94,27 +64,11 @@ func request_AdminService_IsOrgUnique_0(ctx context.Context, marshaler runtime.M
var protoReq UniqueOrgRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AdminService_IsOrgUnique_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.IsOrgUnique(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AdminService_IsOrgUnique_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UniqueOrgRequest
var metadata runtime.ServerMetadata
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_AdminService_IsOrgUnique_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.IsOrgUnique(ctx, &protoReq)
msg, err := client.IsOrgUnique(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
@ -146,33 +100,6 @@ func request_AdminService_GetOrgByID_0(ctx context.Context, marshaler runtime.Ma
}
func local_request_AdminService_GetOrgByID_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OrgID
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.GetOrgByID(ctx, &protoReq)
return msg, metadata, err
}
func request_AdminService_SearchOrgs_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OrgSearchRequest
var metadata runtime.ServerMetadata
@ -190,23 +117,6 @@ func request_AdminService_SearchOrgs_0(ctx context.Context, marshaler runtime.Ma
}
func local_request_AdminService_SearchOrgs_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OrgSearchRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SearchOrgs(ctx, &protoReq)
return msg, metadata, err
}
func request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OrgSetUpRequest
var metadata runtime.ServerMetadata
@ -224,171 +134,6 @@ func request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Mars
}
func local_request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OrgSetUpRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SetUpOrg(ctx, &protoReq)
return msg, metadata, err
}
// RegisterAdminServiceHandlerServer registers the http handlers for service AdminService to "mux".
// UnaryRPC :call AdminServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
func RegisterAdminServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AdminServiceServer) error {
mux.Handle("GET", pattern_AdminService_Healthz_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_Healthz_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_Healthz_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AdminService_Ready_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_Ready_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_Ready_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AdminService_Validate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_Validate_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_Validate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AdminService_IsOrgUnique_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_IsOrgUnique_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_IsOrgUnique_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AdminService_GetOrgByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_GetOrgByID_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_GetOrgByID_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_AdminService_SearchOrgs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_SearchOrgs_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_SearchOrgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_AdminService_SetUpOrg_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AdminService_SetUpOrg_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AdminService_SetUpOrg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterAdminServiceHandlerFromEndpoint is same as RegisterAdminServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterAdminServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
@ -571,19 +316,19 @@ func RegisterAdminServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
}
var (
pattern_AdminService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, ""))
pattern_AdminService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, ""))
pattern_AdminService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, ""))
pattern_AdminService_IsOrgUnique_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_isunique"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_IsOrgUnique_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_isunique"}, ""))
pattern_AdminService_GetOrgByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"orgs", "id"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_GetOrgByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"orgs", "id"}, ""))
pattern_AdminService_SearchOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_search"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_SearchOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_search"}, ""))
pattern_AdminService_SetUpOrg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_setup"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AdminService_SetUpOrg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_setup"}, ""))
)
var (

View File

@ -167,7 +167,7 @@
"200": {
"description": "A successful response.",
"schema": {
"type": "object"
"$ref": "#/definitions/protobufStruct"
}
}
},
@ -178,6 +178,19 @@
}
},
"definitions": {
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
@ -186,6 +199,51 @@
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"v1CreateOrgRequest": {
"type": "object",
"properties": {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3315,7 +3315,7 @@
"200": {
"description": "A successful response.",
"schema": {
"type": "object"
"$ref": "#/definitions/protobufStruct"
}
}
},
@ -3326,6 +3326,19 @@
}
},
"definitions": {
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
@ -3334,6 +3347,51 @@
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"v1AddOrgMemberRequest": {
"type": "object",
"properties": {
@ -3621,7 +3679,7 @@
"type": "string"
},
"data": {
"type": "object"
"$ref": "#/definitions/protobufStruct"
}
}
},