mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:07:23 +00:00
feat: multiple domains (#188)
* check uniqueness on create and register user * change user email, reserve release unique email * usergrant unique aggregate * usergrant uniqueness * validate UserGrant * fix tests * domain is set on username in all orgs * domain in admin * org domain sql * zitadel domain org name * org domains * org iam policy * default org iam policy * SETUP * load login names * login by login name * login name * fix: merge master * fix: merge master * Update internal/user/repository/eventsourcing/user.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix: fix unique domains * fix: rename env variable Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
parent
64b14b4e19
commit
7a6ca24625
@ -32,6 +32,9 @@ InternalAuthZ:
|
||||
- "project.grant.member.read"
|
||||
- "project.grant.member.write"
|
||||
- "project.grant.member.delete"
|
||||
- "iam.policy.read"
|
||||
- "iam.policy.write"
|
||||
- "iam.policy.delete"
|
||||
- Role: 'ORG_OWNER'
|
||||
Permissions:
|
||||
- "org.read"
|
||||
|
@ -48,4 +48,7 @@ export CAOS_OIDC_DEV=true
|
||||
export ZITADEL_COOKIE_DOMAIN=localhost
|
||||
|
||||
#Console
|
||||
export ZITADEL_CONSOLE_ENV_DIR=../../console/src/assets/
|
||||
export ZITADEL_CONSOLE_ENV_DIR=../../console/src/assets/
|
||||
|
||||
#Org
|
||||
export ZITADEL_DEFAULT_DOMAIN=zitadel.ch
|
@ -19,6 +19,7 @@ Mgmt:
|
||||
- x-zitadel-
|
||||
Repository:
|
||||
SearchLimit: 100
|
||||
Domain: $ZITADEL_DEFAULT_DOMAIN
|
||||
Eventstore:
|
||||
ServiceName: 'ManagementAPI'
|
||||
Repository:
|
||||
@ -165,6 +166,7 @@ Admin:
|
||||
- x-zitadel-
|
||||
Repository:
|
||||
SearchLimit: 100
|
||||
Domain: $ZITADEL_DEFAULT_DOMAIN
|
||||
Eventstore:
|
||||
ServiceName: 'Admin'
|
||||
Repository:
|
||||
|
@ -63,6 +63,9 @@ SystemDefaults:
|
||||
Description: Standard lockout policy
|
||||
MaxAttempts: 5
|
||||
ShowLockOutFailures: true
|
||||
OrgIam:
|
||||
Description: Standard org policy
|
||||
UserLoginMustBeDomain: true
|
||||
IamID: 'IAM'
|
||||
SetUp:
|
||||
GlobalOrg: 'Global'
|
||||
@ -71,6 +74,7 @@ SystemDefaults:
|
||||
- Name: 'Global'
|
||||
Domain: 'global.caos.ch'
|
||||
Default: true
|
||||
OrgIamPolicy: true
|
||||
Users:
|
||||
- FirstName: 'Global Org'
|
||||
LastName: 'Administrator'
|
||||
@ -84,7 +88,7 @@ SystemDefaults:
|
||||
Users:
|
||||
- FirstName: 'Zitadel'
|
||||
LastName: 'Administrator'
|
||||
UserName: 'zitadel-admin@caos.ch'
|
||||
UserName: 'zitadel-admin'
|
||||
Email: 'zitadel-admin@caos.ch'
|
||||
Password: 'Password1!'
|
||||
Owners:
|
||||
|
@ -2,6 +2,7 @@ package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
|
||||
admin_model "github.com/caos/zitadel/internal/admin/model"
|
||||
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
@ -9,7 +10,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/eventstore/sdk"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||
policy_es "github.com/caos/zitadel/internal/policy/repository/eventsourcing"
|
||||
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
)
|
||||
@ -31,7 +31,11 @@ type OrgRepo struct {
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) SetUpOrg(ctx context.Context, setUp *admin_model.SetupOrg) (*admin_model.SetupOrg, error) {
|
||||
policy, err := repo.PolicyEventstore.GetPasswordComplexityPolicy(ctx, DEFAULT_POLICY)
|
||||
pwPolicy, err := repo.PolicyEventstore.GetPasswordComplexityPolicy(ctx, DEFAULT_POLICY)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgPolicy, err := repo.OrgEventstore.GetOrgIamPolicy(ctx, DEFAULT_POLICY)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -39,8 +43,7 @@ func (repo *OrgRepo) SetUpOrg(ctx context.Context, setUp *admin_model.SetupOrg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, userAggregates, err := repo.UserEventstore.PrepareCreateUser(ctx, setUp.User, policy, org.AggregateID)
|
||||
user, userAggregates, err := repo.UserEventstore.PrepareCreateUser(ctx, setUp.User, pwPolicy, orgPolicy, org.AggregateID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -77,10 +80,26 @@ func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchR
|
||||
Offset: query.Offset,
|
||||
Limit: query.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: org_view.OrgsToModel(orgs),
|
||||
Result: model.OrgsToModel(orgs),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) {
|
||||
return repo.OrgEventstore.IsOrgUnique(ctx, name, domain)
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) GetOrgIamPolicyByID(ctx context.Context, id string) (*org_model.OrgIamPolicy, error) {
|
||||
return repo.OrgEventstore.GetOrgIamPolicy(ctx, id)
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) CreateOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error) {
|
||||
return repo.OrgEventstore.AddOrgIamPolicy(ctx, policy)
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) ChangeOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error) {
|
||||
return repo.OrgEventstore.ChangeOrgIamPolicy(ctx, policy)
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) RemoveOrgIamPolicy(ctx context.Context, id string) error {
|
||||
return repo.OrgEventstore.RemoveOrgIamPolicy(ctx, id)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package eventstore
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
policy_event "github.com/caos/zitadel/internal/policy/repository/eventsourcing"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
@ -11,6 +12,7 @@ import (
|
||||
type UserRepo struct {
|
||||
UserEvents *usr_event.UserEventstore
|
||||
PolicyEvents *policy_event.PolicyEventstore
|
||||
OrgEvents *org_event.OrgEventstore
|
||||
}
|
||||
|
||||
func (repo *UserRepo) UserByID(ctx context.Context, id string) (project *usr_model.User, err error) {
|
||||
@ -18,11 +20,15 @@ func (repo *UserRepo) UserByID(ctx context.Context, id string) (project *usr_mod
|
||||
}
|
||||
|
||||
func (repo *UserRepo) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
|
||||
policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
pwPolicy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.CreateUser(ctx, user, policy)
|
||||
orgPolicy, err := repo.OrgEvents.GetOrgIamPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.CreateUser(ctx, user, pwPolicy, orgPolicy)
|
||||
}
|
||||
|
||||
func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) {
|
||||
@ -30,9 +36,13 @@ func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, re
|
||||
if resourceOwner != "" {
|
||||
policyResourceOwner = resourceOwner
|
||||
}
|
||||
policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, policyResourceOwner)
|
||||
pwPolicy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, policyResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.RegisterUser(ctx, user, policy, resourceOwner)
|
||||
orgPolicy, err := repo.OrgEvents.GetOrgIamPolicy(ctx, policyResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.RegisterUser(ctx, user, pwPolicy, orgPolicy, resourceOwner)
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
)
|
||||
|
||||
type Org struct {
|
||||
@ -34,7 +34,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
|
||||
}
|
||||
|
||||
func (o *Org) Process(event *es_models.Event) error {
|
||||
org := new(view.OrgView)
|
||||
org := new(org_model.OrgView)
|
||||
|
||||
switch event.Type {
|
||||
case model.OrgAdded:
|
||||
|
@ -24,6 +24,7 @@ type Config struct {
|
||||
Eventstore es_int.Config
|
||||
View types.SQL
|
||||
Spooler spooler.SpoolerConfig
|
||||
Domain string
|
||||
}
|
||||
|
||||
type EsRepository struct {
|
||||
@ -45,7 +46,7 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
|
||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults)
|
||||
|
||||
project, err := es_proj.StartProject(es_proj.ProjectConfig{
|
||||
Eventstore: es,
|
||||
@ -80,7 +81,7 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
||||
|
||||
eventstoreRepos := setup.EventstoreRepos{OrgEvents: org, UserEvents: user, ProjectEvents: project, IamEvents: iam, PolicyEvents: policy}
|
||||
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute(ctx)
|
||||
logging.Log("SERVE-k280HZ").OnError(err).Panic("failed to execute setup")
|
||||
logging.Log("SERVE-djs3R").OnError(err).Panic("failed to execute setup")
|
||||
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient)
|
||||
|
||||
|
@ -167,8 +167,23 @@ func (setUp *initializer) orgs(ctx context.Context, orgs []types.Org) error {
|
||||
}
|
||||
setUp.createdOrgs[iamOrg.Name] = org
|
||||
|
||||
var policy *org_model.OrgIamPolicy
|
||||
if iamOrg.OrgIamPolicy {
|
||||
policy, err = setUp.iamorgpolicy(ctx, org)
|
||||
if err != nil {
|
||||
logging.LogWithFields("SETUP-IlLif", "Org Iam Policy", iamOrg.Name).WithError(err).Error("unable to create iam org policy")
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
policy, err = setUp.repos.OrgEvents.GetOrgIamPolicy(ctx, DEFAULT_POLICY)
|
||||
if err != nil {
|
||||
logging.LogWithFields("SETUP-IS8wS", "Org Iam Policy", iamOrg.Name).WithError(err).Error("unable to get default iam org policy")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ctx = setSetUpContextData(ctx, org.AggregateID)
|
||||
err = setUp.users(ctx, iamOrg.Users)
|
||||
err = setUp.users(ctx, iamOrg.Users, policy)
|
||||
if err != nil {
|
||||
logging.LogWithFields("SETUP-8zfwz", "Org", iamOrg.Name).WithError(err).Error("unable to set up org users")
|
||||
return err
|
||||
@ -193,12 +208,21 @@ func (setUp *initializer) orgs(ctx context.Context, orgs []types.Org) error {
|
||||
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,
|
||||
Name: org.Name,
|
||||
Domains: []*org_model.OrgDomain{&org_model.OrgDomain{Domain: org.Domain}},
|
||||
}
|
||||
return setUp.repos.OrgEvents.CreateOrg(ctx, createOrg)
|
||||
}
|
||||
|
||||
func (setUp *initializer) iamorgpolicy(ctx context.Context, org *org_model.Org) (*org_model.OrgIamPolicy, error) {
|
||||
ctx = setSetUpContextData(ctx, org.AggregateID)
|
||||
policy := &org_model.OrgIamPolicy{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: org.AggregateID},
|
||||
UserLoginMustBeDomain: false,
|
||||
}
|
||||
return setUp.repos.OrgEvents.AddOrgIamPolicy(ctx, policy)
|
||||
}
|
||||
|
||||
func (setUp *initializer) iamOwners(ctx context.Context, owners []string) error {
|
||||
logging.Log("SETUP-dtxfj").Info("setting iam owners")
|
||||
for _, iamOwner := range owners {
|
||||
@ -249,9 +273,9 @@ func (setUp *initializer) setIamProject(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (setUp *initializer) users(ctx context.Context, users []types.User) error {
|
||||
func (setUp *initializer) users(ctx context.Context, users []types.User, orgPolicy *org_model.OrgIamPolicy) error {
|
||||
for _, user := range users {
|
||||
created, err := setUp.user(ctx, user)
|
||||
created, err := setUp.user(ctx, user, orgPolicy)
|
||||
if err != nil {
|
||||
logging.LogWithFields("SETUP-9soer", "Email", user.Email).WithError(err).Error("unable to create iam user")
|
||||
return err
|
||||
@ -261,7 +285,7 @@ func (setUp *initializer) users(ctx context.Context, users []types.User) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (setUp *initializer) user(ctx context.Context, user types.User) (*usr_model.User, error) {
|
||||
func (setUp *initializer) user(ctx context.Context, user types.User, orgPolicy *org_model.OrgIamPolicy) (*usr_model.User, error) {
|
||||
createUser := &usr_model.User{
|
||||
Profile: &usr_model.Profile{
|
||||
UserName: user.UserName,
|
||||
@ -276,7 +300,7 @@ func (setUp *initializer) user(ctx context.Context, user types.User) (*usr_model
|
||||
SecretString: user.Password,
|
||||
},
|
||||
}
|
||||
return setUp.repos.UserEvents.CreateUser(ctx, createUser, setUp.pwComplexityPolicy)
|
||||
return setUp.repos.UserEvents.CreateUser(ctx, createUser, setUp.pwComplexityPolicy, orgPolicy)
|
||||
}
|
||||
|
||||
func (setUp *initializer) orgOwners(ctx context.Context, org *org_model.Org, owners []string) error {
|
||||
|
@ -3,6 +3,7 @@ package view
|
||||
import (
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
)
|
||||
|
||||
@ -10,15 +11,15 @@ const (
|
||||
orgTable = "admin_api.orgs"
|
||||
)
|
||||
|
||||
func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) {
|
||||
func (v *View) OrgByID(orgID string) (*model.OrgView, error) {
|
||||
return org_view.OrgByID(v.Db, orgTable, orgID)
|
||||
}
|
||||
|
||||
func (v *View) SearchOrgs(query *org_model.OrgSearchRequest) ([]*org_view.OrgView, int, error) {
|
||||
func (v *View) SearchOrgs(query *org_model.OrgSearchRequest) ([]*model.OrgView, int, error) {
|
||||
return org_view.SearchOrgs(v.Db, orgTable, query)
|
||||
}
|
||||
|
||||
func (v *View) PutOrg(org *org_view.OrgView) error {
|
||||
func (v *View) PutOrg(org *model.OrgView) error {
|
||||
err := org_view.PutOrg(v.Db, orgTable, org)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -12,4 +12,9 @@ type OrgRepository interface {
|
||||
IsOrgUnique(ctx context.Context, name, domain string) (bool, error)
|
||||
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
|
||||
SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error)
|
||||
|
||||
GetOrgIamPolicyByID(ctx context.Context, id string) (*org_model.OrgIamPolicy, error)
|
||||
CreateOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error)
|
||||
ChangeOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error)
|
||||
RemoveOrgIamPolicy(ctx context.Context, id string) error
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ func (repo *AuthRequestRepo) CheckUsername(ctx context.Context, id, username str
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := repo.View.UserByUsername(username)
|
||||
user, err := repo.View.UserByLoginName(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
)
|
||||
|
||||
type OrgRepository struct {
|
||||
@ -24,6 +24,6 @@ func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.Or
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: view.OrgsToModel(members),
|
||||
Result: model.OrgsToModel(members),
|
||||
}, nil
|
||||
}
|
||||
|
@ -34,11 +34,15 @@ func (repo *UserRepo) Register(ctx context.Context, registerUser *model.User, or
|
||||
if resourceOwner != "" {
|
||||
policyResourceOwner = resourceOwner
|
||||
}
|
||||
policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, policyResourceOwner)
|
||||
pwPolicy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, policyResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, aggregates, err := repo.UserEvents.PrepareRegisterUser(ctx, registerUser, policy, resourceOwner)
|
||||
orgPolicy, err := repo.OrgEvents.GetOrgIamPolicy(ctx, policyResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, aggregates, err := repo.UserEvents.PrepareRegisterUser(ctx, registerUser, pwPolicy, orgPolicy, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
|
||||
)
|
||||
@ -123,7 +123,7 @@ func grantRespToOrgResp(grants *grant_model.UserGrantSearchResponse) *grant_mode
|
||||
return resp
|
||||
}
|
||||
|
||||
func orgRespToOrgResp(orgs []*org_view.OrgView, count int) *grant_model.ProjectOrgSearchResponse {
|
||||
func orgRespToOrgResp(orgs []*org_view_model.OrgView, count int) *grant_model.ProjectOrgSearchResponse {
|
||||
resp := &grant_model.ProjectOrgSearchResponse{
|
||||
TotalResult: uint64(count),
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ type EventstoreRepos struct {
|
||||
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []spooler.Handler {
|
||||
return []spooler.Handler{
|
||||
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}},
|
||||
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, orgEvents: repos.OrgEvents},
|
||||
&UserSession{handler: handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount}, userEvents: repos.UserEvents},
|
||||
&Token{handler: handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount}},
|
||||
&Key{handler: handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount}},
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -33,7 +33,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
|
||||
}
|
||||
|
||||
func (o *Org) Process(event *es_models.Event) error {
|
||||
org := new(view.OrgView)
|
||||
org := new(org_model.OrgView)
|
||||
|
||||
switch event.Type {
|
||||
case model.OrgAdded:
|
||||
|
@ -1,6 +1,11 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"time"
|
||||
|
||||
@ -9,13 +14,13 @@ import (
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
handler
|
||||
eventstore eventstore.Eventstore
|
||||
orgEvents *org_events.OrgEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
@ -33,15 +38,29 @@ func (p *User) EventQuery() (*models.SearchQuery, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventsourcing.UserQuery(sequence), nil
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(es_model.UserAggregate, org_es_model.OrgAggregate).
|
||||
LatestSequenceFilter(sequence), nil
|
||||
}
|
||||
|
||||
func (p *User) Process(event *models.Event) (err error) {
|
||||
func (u *User) Process(event *models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case es_model.UserAggregate:
|
||||
return u.ProcessUser(event)
|
||||
case org_es_model.OrgAggregate:
|
||||
return u.ProcessOrg(event)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *User) ProcessUser(event *models.Event) (err error) {
|
||||
user := new(view_model.UserView)
|
||||
switch event.Type {
|
||||
case es_model.UserAdded,
|
||||
es_model.UserRegistered:
|
||||
user.AppendEvent(event)
|
||||
p.fillLoginNames(user)
|
||||
case es_model.UserProfileChanged,
|
||||
es_model.UserEmailChanged,
|
||||
es_model.UserEmailVerified,
|
||||
@ -70,7 +89,72 @@ func (p *User) Process(event *models.Event) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.PutUser(user)
|
||||
return p.view.PutUser(user, user.Sequence)
|
||||
}
|
||||
|
||||
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
|
||||
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(user.ResourceOwner))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policy, err := u.orgEvents.GetOrgIamPolicy(context.Background(), user.ResourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.LoginNames = getLoginNames(policy, user.UserName, org.Domains)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLoginNames(policy *org_model.OrgIamPolicy, userName string, domains []*org_model.OrgDomain) []string {
|
||||
loginNames := make([]string, 0)
|
||||
if !policy.UserLoginMustBeDomain {
|
||||
return []string{userName}
|
||||
}
|
||||
for _, d := range domains {
|
||||
if d.Verified {
|
||||
loginNames = append(loginNames, userName+"@"+d.Domain)
|
||||
}
|
||||
}
|
||||
return loginNames
|
||||
}
|
||||
|
||||
func (u *User) ProcessOrg(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case org_es_model.OrgDomainVerified,
|
||||
org_es_model.OrgDomainRemoved,
|
||||
org_es_model.OrgIamPolicyAdded,
|
||||
org_es_model.OrgIamPolicyChanged,
|
||||
org_es_model.OrgIamPolicyRemoved:
|
||||
return u.fillLoginNamesOnOrgUsers(event)
|
||||
default:
|
||||
return u.view.ProcessedUserSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
|
||||
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policy, err := u.orgEvents.GetOrgIamPolicy(context.Background(), event.ResourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users, err := u.view.UsersByOrgID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
user.LoginNames = getLoginNames(policy, user.UserName, org.Domains)
|
||||
err := u.view.PutUser(user, event.Sequence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *User) OnError(event *models.Event, err error) error {
|
||||
|
@ -189,7 +189,6 @@ func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suf
|
||||
ID: u.iamProjectID + member.UserID,
|
||||
ResourceOwner: u.iamID,
|
||||
OrgName: u.iamID,
|
||||
OrgDomain: u.iamID,
|
||||
ProjectID: u.iamProjectID,
|
||||
UserID: member.UserID,
|
||||
RoleKeys: member.Roles,
|
||||
@ -334,7 +333,6 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
|
||||
}
|
||||
|
||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
||||
grant.OrgDomain = org.Domain
|
||||
grant.OrgName = org.Name
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ func Start(conf Config, authZ auth.Config, systemDefaults sd.SystemDefaults, aut
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
|
||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es}, systemDefaults)
|
||||
|
||||
repos := handler.EventstoreRepos{UserEvents: user, ProjectEvents: project, OrgEvents: org, IamEvents: iam}
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults)
|
||||
|
@ -3,6 +3,7 @@ package view
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/org/model"
|
||||
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
)
|
||||
|
||||
@ -10,15 +11,15 @@ const (
|
||||
orgTable = "auth.orgs"
|
||||
)
|
||||
|
||||
func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) {
|
||||
func (v *View) OrgByID(orgID string) (*org_model.OrgView, error) {
|
||||
return org_view.OrgByID(v.Db, orgTable, orgID)
|
||||
}
|
||||
|
||||
func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_view.OrgView, int, error) {
|
||||
func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, int, error) {
|
||||
return org_view.SearchOrgs(v.Db, orgTable, req)
|
||||
}
|
||||
|
||||
func (v *View) PutOrg(org *org_view.OrgView) error {
|
||||
func (v *View) PutOrg(org *org_model.OrgView) error {
|
||||
err := org_view.PutOrg(v.Db, orgTable, org)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -19,6 +19,13 @@ func (v *View) UserByUsername(userName string) (*model.UserView, error) {
|
||||
return view.UserByUserName(v.Db, userTable, userName)
|
||||
}
|
||||
|
||||
func (v *View) UserByLoginName(loginName string) (*model.UserView, error) {
|
||||
return view.UserByLoginName(v.Db, userTable, loginName)
|
||||
}
|
||||
|
||||
func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) {
|
||||
return view.UsersByOrgID(v.Db, userTable, orgID)
|
||||
}
|
||||
func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserView, int, error) {
|
||||
return view.SearchUsers(v.Db, userTable, request)
|
||||
}
|
||||
@ -35,12 +42,12 @@ func (v *View) UserMfas(userID string) ([]*usr_model.MultiFactor, error) {
|
||||
return view.UserMfas(v.Db, userTable, userID)
|
||||
}
|
||||
|
||||
func (v *View) PutUser(user *model.UserView) error {
|
||||
func (v *View) PutUser(user *model.UserView, sequence uint64) error {
|
||||
err := view.PutUser(v.Db, userTable, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedUserSequence(user.Sequence)
|
||||
return v.ProcessedUserSequence(sequence)
|
||||
}
|
||||
|
||||
func (v *View) DeleteUser(userID string, eventSequence uint64) error {
|
||||
|
@ -108,7 +108,6 @@ func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suf
|
||||
ID: u.iamProjectID + member.UserID,
|
||||
ResourceOwner: u.iamID,
|
||||
OrgName: u.iamID,
|
||||
OrgDomain: u.iamID,
|
||||
ProjectID: u.iamProjectID,
|
||||
UserID: member.UserID,
|
||||
RoleKeys: member.Roles,
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/notification/providers/email"
|
||||
"github.com/caos/zitadel/internal/notification/providers/twilio"
|
||||
"github.com/caos/zitadel/internal/notification/templates"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
pol "github.com/caos/zitadel/internal/policy"
|
||||
)
|
||||
|
||||
@ -50,6 +51,7 @@ type DefaultPolicies struct {
|
||||
Age pol.PasswordAgePolicyDefault
|
||||
Complexity pol.PasswordComplexityPolicyDefault
|
||||
Lockout pol.PasswordLockoutPolicyDefault
|
||||
OrgIam org_model.OrgIamPolicy
|
||||
}
|
||||
|
||||
type Notifications struct {
|
||||
|
@ -16,11 +16,12 @@ type User struct {
|
||||
}
|
||||
|
||||
type Org struct {
|
||||
Name string
|
||||
Domain string
|
||||
Users []User
|
||||
Owners []string
|
||||
Projects []Project
|
||||
Name string
|
||||
Domain string
|
||||
OrgIamPolicy bool
|
||||
Users []User
|
||||
Owners []string
|
||||
Projects []Project
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
|
@ -7,6 +7,8 @@ Login:
|
||||
Title: Anmeldung
|
||||
Description: Gib deine Benutzerdaten ein.
|
||||
Username: Benutzername
|
||||
Loginname: Loginname
|
||||
LoginnamePlaceHolder: username@domain
|
||||
|
||||
UserSelection:
|
||||
Title: Account auswählen
|
||||
|
@ -2,6 +2,8 @@ Login:
|
||||
Title: Login
|
||||
Description: Enter your logindata.
|
||||
Username: Username
|
||||
Loginname: Loginname
|
||||
LoginnamePlaceHolder: username@domain
|
||||
|
||||
UserSelection:
|
||||
Title: Select account
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
{{template "main-top" .}}
|
||||
|
||||
<h1>{{t "Login.Title"}}</h1>
|
||||
@ -9,8 +10,8 @@
|
||||
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label class="label" for="username">{{t "Login.Username"}}</label>
|
||||
<input class="input" type="text" id="username" name="username" value="{{ .UserName }}" autocomplete="username" autofocus required>
|
||||
<label class="label" for="username">{{t "Login.Loginname"}}</label>
|
||||
<input class="input" type="text" id="username" name="username" placeholder="{{t "Login.LoginnamePlaceHolder"}}" value="{{ .UserName }}" autocomplete="username" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -2,16 +2,15 @@ package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
mgmt_view "github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
)
|
||||
|
||||
type OrgRepository struct {
|
||||
@ -26,12 +25,12 @@ func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.O
|
||||
return repo.OrgEventstore.OrgByID(ctx, org)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.OrgView, error) {
|
||||
org, err := repo.View.OrgByDomain(domain)
|
||||
func (repo *OrgRepository) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error) {
|
||||
verifiedDomain, err := repo.View.VerifiedOrgDomain(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return view.OrgToModel(org), nil
|
||||
return repo.OrgByID(ctx, verifiedDomain.OrgID)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error) {
|
||||
@ -46,6 +45,31 @@ func (repo *OrgRepository) ReactivateOrg(ctx context.Context, id string) (*org_m
|
||||
return repo.OrgEventstore.ReactivateOrg(ctx, id)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) SearchMyOrgDomains(ctx context.Context, request *org_model.OrgDomainSearchRequest) (*org_model.OrgDomainSearchResponse, error) {
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
request.Queries = append(request.Queries, &org_model.OrgDomainSearchQuery{Key: org_model.ORGDOMAINSEARCHKEY_ORG_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: auth.GetCtxData(ctx).OrgID})
|
||||
domains, count, err := repo.View.SearchOrgDomains(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org_model.OrgDomainSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: model.OrgDomainsToModel(domains),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) AddMyOrgDomain(ctx context.Context, domain *org_model.OrgDomain) (*org_model.OrgDomain, error) {
|
||||
domain.AggregateID = auth.GetCtxData(ctx).OrgID
|
||||
return repo.OrgEventstore.AddOrgDomain(ctx, domain)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) RemoveMyOrgDomain(ctx context.Context, domain string) error {
|
||||
d := org_model.NewOrgDomain(auth.GetCtxData(ctx).OrgID, domain)
|
||||
return repo.OrgEventstore.RemoveOrgDomain(ctx, d)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64) (*org_model.OrgChanges, error) {
|
||||
changes, err := repo.OrgEventstore.OrgChanges(ctx, id, lastSequence, limit)
|
||||
if err != nil {
|
||||
@ -76,7 +100,7 @@ func (repo *OrgRepository) RemoveMyOrgMember(ctx context.Context, userID string)
|
||||
|
||||
func (repo *OrgRepository) SearchMyOrgMembers(ctx context.Context, request *org_model.OrgMemberSearchRequest) (*org_model.OrgMemberSearchResponse, error) {
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
request.Queries[len(request.Queries)-1] = &org_model.OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_ORG_ID, Method: model.SEARCHMETHOD_EQUALS, Value: auth.GetCtxData(ctx).OrgID}
|
||||
request.Queries[len(request.Queries)-1] = &org_model.OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_ORG_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: auth.GetCtxData(ctx).OrgID}
|
||||
members, count, err := repo.View.SearchOrgMembers(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -85,7 +109,7 @@ func (repo *OrgRepository) SearchMyOrgMembers(ctx context.Context, request *org_
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: view.OrgMembersToModel(members),
|
||||
Result: model.OrgMembersToModel(members),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
policy_event "github.com/caos/zitadel/internal/policy/repository/eventsourcing"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
@ -15,6 +16,7 @@ type UserRepo struct {
|
||||
SearchLimit uint64
|
||||
UserEvents *usr_event.UserEventstore
|
||||
PolicyEvents *policy_event.PolicyEventstore
|
||||
OrgEvents *org_event.OrgEventstore
|
||||
View *view.View
|
||||
}
|
||||
|
||||
@ -23,11 +25,15 @@ func (repo *UserRepo) UserByID(ctx context.Context, id string) (project *usr_mod
|
||||
}
|
||||
|
||||
func (repo *UserRepo) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
|
||||
policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
pwPolicy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.CreateUser(ctx, user, policy)
|
||||
orgPolicy, err := repo.OrgEvents.GetOrgIamPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.CreateUser(ctx, user, pwPolicy, orgPolicy)
|
||||
}
|
||||
|
||||
func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) {
|
||||
@ -35,11 +41,15 @@ func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, re
|
||||
if resourceOwner != "" {
|
||||
policyResourceOwner = resourceOwner
|
||||
}
|
||||
policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, policyResourceOwner)
|
||||
pwPolicy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, policyResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.RegisterUser(ctx, user, policy, resourceOwner)
|
||||
orgPolicy, err := repo.OrgEvents.GetOrgIamPolicy(ctx, auth.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserEvents.RegisterUser(ctx, user, pwPolicy, orgPolicy, resourceOwner)
|
||||
}
|
||||
|
||||
func (repo *UserRepo) DeactivateUser(ctx context.Context, id string) (*usr_model.User, error) {
|
||||
|
@ -43,6 +43,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
|
||||
&UserGrant{handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, projectEvents: repos.ProjectEvents, userEvents: repos.UserEvents, orgEvents: repos.OrgEvents},
|
||||
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
||||
&OrgMember{handler: handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount}, userEvents: repos.UserEvents},
|
||||
&OrgDomain{handler: handler{view, bulkLimit, configs.cycleDuration("OrgDomain"), errorCount}},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,13 @@ package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
)
|
||||
|
||||
type Org struct {
|
||||
@ -34,7 +34,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
|
||||
}
|
||||
|
||||
func (o *Org) Process(event *es_models.Event) error {
|
||||
org := new(view.OrgView)
|
||||
org := new(org_model.OrgView)
|
||||
|
||||
switch event.Type {
|
||||
case model.OrgAdded:
|
||||
|
@ -0,0 +1,100 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
)
|
||||
|
||||
type OrgDomain struct {
|
||||
handler
|
||||
}
|
||||
|
||||
const (
|
||||
orgDomainTable = "management.org_domains"
|
||||
)
|
||||
|
||||
func (d *OrgDomain) MinimumCycleDuration() time.Duration { return d.cycleDuration }
|
||||
|
||||
func (d *OrgDomain) ViewModel() string {
|
||||
return orgDomainTable
|
||||
}
|
||||
|
||||
func (d *OrgDomain) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := d.view.GetLatestOrgDomainSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(model.OrgAggregate).
|
||||
LatestSequenceFilter(sequence), nil
|
||||
}
|
||||
|
||||
func (d *OrgDomain) Process(event *models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case model.OrgAggregate:
|
||||
err = d.processOrgDomain(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *OrgDomain) processOrgDomain(event *models.Event) (err error) {
|
||||
domain := new(org_model.OrgDomainView)
|
||||
switch event.Type {
|
||||
case model.OrgDomainAdded:
|
||||
domain.AppendEvent(event)
|
||||
case model.OrgDomainVerified:
|
||||
err = domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err = d.view.OrgDomainByOrgIDAndDomain(event.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain.AppendEvent(event)
|
||||
case model.OrgDomainPrimarySet:
|
||||
err = domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err = d.view.OrgDomainByOrgIDAndDomain(event.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingDomains, err := d.view.OrgDomainsByOrgID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, existing := range existingDomains {
|
||||
existing.Primary = false
|
||||
err := d.view.PutOrgDomain(existing, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
domain.AppendEvent(event)
|
||||
case model.OrgDomainRemoved:
|
||||
err = domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.view.DeleteOrgDomain(domain.Domain, event.Sequence)
|
||||
default:
|
||||
return d.view.ProcessedOrgDomainSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.view.PutOrgDomain(domain, domain.Sequence)
|
||||
}
|
||||
|
||||
func (d *OrgDomain) OnError(event *models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-us4sj", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgdomain handler")
|
||||
return spooler.HandleError(event, err, d.view.GetLatestOrgDomainFailedEvent, d.view.ProcessedOrgDomainFailedEvent, d.view.ProcessedOrgDomainSequence, d.errorCountUntilSkip)
|
||||
}
|
@ -3,13 +3,13 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
view_model "github.com/caos/zitadel/internal/org/repository/view"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
@ -51,7 +51,7 @@ func (m *OrgMember) Process(event *models.Event) (err error) {
|
||||
}
|
||||
|
||||
func (m *OrgMember) processOrgMember(event *models.Event) (err error) {
|
||||
member := new(view_model.OrgMemberView)
|
||||
member := new(org_model.OrgMemberView)
|
||||
switch event.Type {
|
||||
case model.OrgMemberAdded:
|
||||
member.AppendEvent(event)
|
||||
@ -106,7 +106,7 @@ func (m *OrgMember) processUser(event *models.Event) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OrgMember) fillData(member *view_model.OrgMemberView) (err error) {
|
||||
func (m *OrgMember) fillData(member *org_model.OrgMemberView) (err error) {
|
||||
user, err := m.userEvents.UserByID(context.Background(), member.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -115,7 +115,7 @@ func (m *OrgMember) fillData(member *view_model.OrgMemberView) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OrgMember) fillUserData(member *view_model.OrgMemberView, user *usr_model.User) {
|
||||
func (m *OrgMember) fillUserData(member *org_model.OrgMemberView, user *usr_model.User) {
|
||||
member.UserName = user.UserName
|
||||
member.FirstName = user.FirstName
|
||||
member.LastName = user.LastName
|
||||
|
@ -95,7 +95,6 @@ func (p *ProjectGrant) Process(event *models.Event) (err error) {
|
||||
}
|
||||
|
||||
func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, org *org_model.Org) {
|
||||
grantedProject.OrgDomain = org.Domain
|
||||
grantedProject.OrgName = org.Name
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,6 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
|
||||
}
|
||||
|
||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
||||
grant.OrgDomain = org.Domain
|
||||
grant.OrgName = org.Name
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
type Config struct {
|
||||
SearchLimit uint64
|
||||
Domain string
|
||||
Eventstore es_int.Config
|
||||
View types.SQL
|
||||
Spooler spooler.SpoolerConfig
|
||||
@ -80,7 +81,8 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
|
||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults)
|
||||
|
||||
iam, err := es_iam.StartIam(es_iam.IamConfig{
|
||||
Eventstore: es,
|
||||
Cache: conf.Eventstore.Cache,
|
||||
@ -95,7 +97,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRe
|
||||
spooler: spool,
|
||||
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, view, roles},
|
||||
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view, roles},
|
||||
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, policy, view},
|
||||
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, policy, org, view},
|
||||
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
|
||||
PolicyRepo: eventstore.PolicyRepo{policy},
|
||||
IamRepository: eventstore.IamRepository{iam},
|
||||
|
@ -2,6 +2,7 @@ package view
|
||||
|
||||
import (
|
||||
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
)
|
||||
|
||||
@ -9,15 +10,11 @@ const (
|
||||
orgTable = "management.orgs"
|
||||
)
|
||||
|
||||
func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) {
|
||||
func (v *View) OrgByID(orgID string) (*model.OrgView, error) {
|
||||
return org_view.OrgByID(v.Db, orgTable, orgID)
|
||||
}
|
||||
|
||||
func (v *View) OrgByDomain(domain string) (*org_view.OrgView, error) {
|
||||
return org_view.GetGlobalOrgByDomain(v.Db, orgTable, domain)
|
||||
}
|
||||
|
||||
func (v *View) PutOrg(org *org_view.OrgView) error {
|
||||
func (v *View) PutOrg(org *model.OrgView) error {
|
||||
err := org_view.PutOrg(v.Db, orgTable, org)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -0,0 +1,63 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
global_view "github.com/caos/zitadel/internal/view"
|
||||
)
|
||||
|
||||
const (
|
||||
orgDomainTable = "management.org_domains"
|
||||
)
|
||||
|
||||
func (v *View) OrgDomainByOrgIDAndDomain(orgID, domain string) (*model.OrgDomainView, error) {
|
||||
return view.OrgDomainByOrgIDAndDomain(v.Db, orgDomainTable, orgID, domain)
|
||||
}
|
||||
|
||||
func (v *View) OrgDomainsByOrgID(domain string) ([]*model.OrgDomainView, error) {
|
||||
return view.OrgDomainsByOrgID(v.Db, orgDomainTable, domain)
|
||||
}
|
||||
|
||||
func (v *View) VerifiedOrgDomain(domain string) (*model.OrgDomainView, error) {
|
||||
return view.VerifiedOrgDomain(v.Db, orgDomainTable, domain)
|
||||
}
|
||||
|
||||
func (v *View) SearchOrgDomains(request *org_model.OrgDomainSearchRequest) ([]*model.OrgDomainView, int, error) {
|
||||
return view.SearchOrgDomains(v.Db, orgDomainTable, request)
|
||||
}
|
||||
|
||||
func (v *View) PutOrgDomain(org *model.OrgDomainView, sequence uint64) error {
|
||||
err := view.PutOrgDomain(v.Db, orgDomainTable, org)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sequence != 0 {
|
||||
return v.ProcessedOrgDomainSequence(sequence)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) DeleteOrgDomain(domain string, eventSequence uint64) error {
|
||||
err := view.DeleteOrgDomain(v.Db, orgDomainTable, domain)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return v.ProcessedOrgDomainSequence(eventSequence)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestOrgDomainSequence() (uint64, error) {
|
||||
return v.latestSequence(orgDomainTable)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedOrgDomainSequence(eventSequence uint64) error {
|
||||
return v.saveCurrentSequence(orgDomainTable, eventSequence)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestOrgDomainFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||
return v.latestFailedEvent(orgDomainTable, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedOrgDomainFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
@ -3,6 +3,7 @@ package view
|
||||
import (
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
global_view "github.com/caos/zitadel/internal/view"
|
||||
)
|
||||
|
||||
@ -10,19 +11,19 @@ const (
|
||||
orgMemberTable = "management.org_members"
|
||||
)
|
||||
|
||||
func (v *View) OrgMemberByIDs(orgID, userID string) (*view.OrgMemberView, error) {
|
||||
func (v *View) OrgMemberByIDs(orgID, userID string) (*model.OrgMemberView, error) {
|
||||
return view.OrgMemberByIDs(v.Db, orgMemberTable, orgID, userID)
|
||||
}
|
||||
|
||||
func (v *View) SearchOrgMembers(request *org_model.OrgMemberSearchRequest) ([]*view.OrgMemberView, int, error) {
|
||||
func (v *View) SearchOrgMembers(request *org_model.OrgMemberSearchRequest) ([]*model.OrgMemberView, int, error) {
|
||||
return view.SearchOrgMembers(v.Db, orgMemberTable, request)
|
||||
}
|
||||
|
||||
func (v *View) OrgMembersByUserID(userID string) ([]*view.OrgMemberView, error) {
|
||||
func (v *View) OrgMembersByUserID(userID string) ([]*model.OrgMemberView, error) {
|
||||
return view.OrgMembersByUserID(v.Db, orgMemberTable, userID)
|
||||
}
|
||||
|
||||
func (v *View) PutOrgMember(org *view.OrgMemberView, sequence uint64) error {
|
||||
func (v *View) PutOrgMember(org *model.OrgMemberView, sequence uint64) error {
|
||||
err := view.PutOrgMember(v.Db, orgMemberTable, org)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -8,12 +8,16 @@ import (
|
||||
|
||||
type OrgRepository interface {
|
||||
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
|
||||
OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.OrgView, error)
|
||||
OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error)
|
||||
UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error)
|
||||
DeactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
|
||||
ReactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
|
||||
OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64) (*org_model.OrgChanges, error)
|
||||
|
||||
SearchMyOrgDomains(ctx context.Context, request *org_model.OrgDomainSearchRequest) (*org_model.OrgDomainSearchResponse, error)
|
||||
AddMyOrgDomain(ctx context.Context, domain *org_model.OrgDomain) (*org_model.OrgDomain, error)
|
||||
RemoveMyOrgDomain(ctx context.Context, domain string) error
|
||||
|
||||
SearchMyOrgMembers(ctx context.Context, request *org_model.OrgMemberSearchRequest) (*org_model.OrgMemberSearchResponse, error)
|
||||
AddMyOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
||||
ChangeMyOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
||||
|
@ -13,4 +13,5 @@ const (
|
||||
SEARCHMETHOD_GREATER_THAN
|
||||
SEARCHMETHOD_LESS_THAN
|
||||
SEARCHMETHOD_IN
|
||||
SEARCHMETHOD_EQUALS_IN_ARRAY
|
||||
)
|
||||
|
18
internal/org/model/domain.go
Normal file
18
internal/org/model/domain.go
Normal file
@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
import es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
type OrgDomain struct {
|
||||
es_models.ObjectRoot
|
||||
Domain string
|
||||
Primary bool
|
||||
Verified bool
|
||||
}
|
||||
|
||||
func NewOrgDomain(orgID, domain string) *OrgDomain {
|
||||
return &OrgDomain{ObjectRoot: es_models.ObjectRoot{AggregateID: orgID}, Domain: domain}
|
||||
}
|
||||
|
||||
func (domain *OrgDomain) IsValid() bool {
|
||||
return domain.AggregateID != "" && domain.Domain != ""
|
||||
}
|
52
internal/org/model/domain_view.go
Normal file
52
internal/org/model/domain_view.go
Normal file
@ -0,0 +1,52 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OrgDomainView struct {
|
||||
OrgID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Domain string
|
||||
Primary bool
|
||||
Verified bool
|
||||
}
|
||||
|
||||
type OrgDomainSearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn OrgDomainSearchKey
|
||||
Asc bool
|
||||
Queries []*OrgDomainSearchQuery
|
||||
}
|
||||
|
||||
type OrgDomainSearchKey int32
|
||||
|
||||
const (
|
||||
ORGDOMAINSEARCHKEY_UNSPECIFIED OrgDomainSearchKey = iota
|
||||
ORGDOMAINSEARCHKEY_DOMAIN
|
||||
ORGDOMAINSEARCHKEY_ORG_ID
|
||||
ORGDOMAINSEARCHKEY_VERIFIED
|
||||
ORGDOMAINSEARCHKEY_PRIMARY
|
||||
)
|
||||
|
||||
type OrgDomainSearchQuery struct {
|
||||
Key OrgDomainSearchKey
|
||||
Method model.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type OrgDomainSearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*OrgDomainView
|
||||
}
|
||||
|
||||
func (r *OrgDomainSearchRequest) EnsureLimit(limit uint64) {
|
||||
if r.Limit == 0 || r.Limit > limit {
|
||||
r.Limit = limit
|
||||
}
|
||||
}
|
@ -2,17 +2,19 @@ package model
|
||||
|
||||
import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"strings"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
)
|
||||
|
||||
type Org struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
State OrgState
|
||||
Name string
|
||||
Domain string
|
||||
State OrgState
|
||||
Name string
|
||||
Domains []*OrgDomain
|
||||
|
||||
Members []*OrgMember
|
||||
Members []*OrgMember
|
||||
OrgIamPolicy *OrgIamPolicy
|
||||
}
|
||||
type OrgChanges struct {
|
||||
Changes []*OrgChange
|
||||
@ -43,7 +45,16 @@ func (o *Org) IsActive() bool {
|
||||
}
|
||||
|
||||
func (o *Org) IsValid() bool {
|
||||
return o.Name != "" && o.Domain != ""
|
||||
return o.Name != ""
|
||||
}
|
||||
|
||||
func (o *Org) ContainsDomain(domain *OrgDomain) bool {
|
||||
for _, d := range o.Domains {
|
||||
if d.Domain == domain.Domain {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *Org) ContainsMember(userID string) bool {
|
||||
@ -54,3 +65,11 @@ func (o *Org) ContainsMember(userID string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *Org) nameForDomain(iamDomain string) string {
|
||||
return strings.ToLower(strings.ReplaceAll(o.Name, " ", "-") + "." + iamDomain)
|
||||
}
|
||||
|
||||
func (o *Org) AddIAMDomain(iamDomain string) {
|
||||
o.Domains = append(o.Domains, &OrgDomain{Domain: o.nameForDomain(iamDomain), Verified: true, Primary: true})
|
||||
}
|
||||
|
21
internal/org/model/org_iam_policy.go
Normal file
21
internal/org/model/org_iam_policy.go
Normal file
@ -0,0 +1,21 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type OrgIamPolicy struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Description string
|
||||
State PolicyState
|
||||
UserLoginMustBeDomain bool
|
||||
Default bool
|
||||
}
|
||||
|
||||
type PolicyState int32
|
||||
|
||||
const (
|
||||
POLICYSTATE_ACTIVE PolicyState = iota
|
||||
POLICYSTATE_REMOVED
|
||||
)
|
@ -42,7 +42,7 @@ const (
|
||||
type OrgMemberSearchQuery struct {
|
||||
Key OrgMemberSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type OrgMemberSearchResponse struct {
|
||||
|
@ -15,8 +15,7 @@ type OrgView struct {
|
||||
ResourceOwner string
|
||||
Sequence uint64
|
||||
|
||||
Name string
|
||||
Domain string
|
||||
Name string
|
||||
}
|
||||
|
||||
type OrgSearchRequest struct {
|
||||
@ -41,7 +40,7 @@ const (
|
||||
type OrgSearchQuery struct {
|
||||
Key OrgSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type OrgSearchResult struct {
|
||||
@ -66,8 +65,7 @@ func OrgViewToOrg(o *OrgView) *Org {
|
||||
ResourceOwner: o.ResourceOwner,
|
||||
Sequence: o.Sequence,
|
||||
},
|
||||
Domain: o.Domain,
|
||||
Name: o.Name,
|
||||
State: o.State,
|
||||
Name: o.Name,
|
||||
State: o.State,
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ package eventsourcing
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"log"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
|
||||
@ -19,17 +19,24 @@ import (
|
||||
|
||||
type OrgEventstore struct {
|
||||
eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
IAMDomain string
|
||||
idGenerator id.Generator
|
||||
defaultOrgIamPolicy *org_model.OrgIamPolicy
|
||||
}
|
||||
|
||||
type OrgConfig struct {
|
||||
eventstore.Eventstore
|
||||
IAMDomain string
|
||||
}
|
||||
|
||||
func StartOrg(conf OrgConfig) *OrgEventstore {
|
||||
func StartOrg(conf OrgConfig, defaults systemdefaults.SystemDefaults) *OrgEventstore {
|
||||
policy := defaults.DefaultPolicies.OrgIam
|
||||
policy.Default = true
|
||||
return &OrgEventstore{
|
||||
Eventstore: conf.Eventstore,
|
||||
idGenerator: id.SonyFlakeGenerator,
|
||||
Eventstore: conf.Eventstore,
|
||||
idGenerator: id.SonyFlakeGenerator,
|
||||
IAMDomain: conf.IAMDomain,
|
||||
defaultOrgIamPolicy: &policy,
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +44,8 @@ func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_mod
|
||||
if orgModel == nil || !orgModel.IsValid() {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "EVENT-OeLSk", "org not valid")
|
||||
}
|
||||
orgModel.AddIAMDomain(es.IAMDomain)
|
||||
|
||||
id, err := es.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, nil, errors.ThrowInternal(err, "EVENT-OwciI", "id gen failed")
|
||||
@ -138,6 +147,53 @@ func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_
|
||||
return model.OrgToModel(org), nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) AddOrgDomain(ctx context.Context, domain *org_model.OrgDomain) (*org_model.OrgDomain, error) {
|
||||
if !domain.IsValid() {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-8sFJW", "domain is invalid")
|
||||
}
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(domain.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoDomain := model.OrgDomainFromModel(domain)
|
||||
aggregate := OrgDomainAddedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoDomain)
|
||||
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, aggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, d := model.GetDomain(repoOrg.Domains, domain.Domain); d != nil {
|
||||
return model.OrgDomainToModel(d), nil
|
||||
}
|
||||
return nil, errors.ThrowInternal(nil, "EVENT-ISOP0", "Could not find org in list")
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) RemoveOrgDomain(ctx context.Context, domain *org_model.OrgDomain) error {
|
||||
if domain.Domain == "" {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-SJsK3", "Domain is required")
|
||||
}
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(domain.AggregateID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !existing.ContainsDomain(domain) {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-Sjdi3", "Domain doesn't exist on project")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoDomain := model.OrgDomainFromModel(domain)
|
||||
orgAggregates, err := OrgDomainRemovedAggregate(ctx, es.Eventstore.AggregateCreator(), repoOrg, repoDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregates...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64) (*org_model.OrgChanges, error) {
|
||||
query := ChangesQuery(id, lastSequence)
|
||||
|
||||
@ -147,7 +203,7 @@ func (es *OrgEventstore) OrgChanges(ctx context.Context, id string, lastSequence
|
||||
return nil, errors.ThrowInternal(err, "EVENT-328b1", "unable to get current user")
|
||||
}
|
||||
if len(events) == 0 {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "EVENT-FpQqK", "no objects found")
|
||||
return nil, errors.ThrowNotFound(nil, "EVENT-FpQqK", "no objects found")
|
||||
}
|
||||
|
||||
result := make([]*org_model.OrgChange, 0)
|
||||
@ -277,3 +333,74 @@ func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model.
|
||||
orgAggregate := orgMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoMember)
|
||||
return es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate)
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) GetOrgIamPolicy(ctx context.Context, orgID string) (*org_model.OrgIamPolicy, error) {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(orgID))
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
if existing != nil && existing.OrgIamPolicy != nil {
|
||||
return existing.OrgIamPolicy, nil
|
||||
}
|
||||
return es.defaultOrgIamPolicy, nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) AddOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error) {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(policy.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.OrgIamPolicy != nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-7Usj3", "Policy already exists")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoPolicy := model.OrgIamPolicyFromModel(policy)
|
||||
orgAggregate := OrgIamPolicyAddedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return model.OrgIamPolicyToModel(repoOrg.OrgIamPolicy), nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) ChangeOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error) {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(policy.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.OrgIamPolicy == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-8juSd", "Policy doesnt exist")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoPolicy := model.OrgIamPolicyFromModel(policy)
|
||||
orgAggregate := OrgIamPolicyChangedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return model.OrgIamPolicyToModel(repoOrg.OrgIamPolicy), nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) RemoveOrgIamPolicy(ctx context.Context, orgID string) error {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(orgID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing.OrgIamPolicy == nil {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-z6Dse", "Policy doesnt exist")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
orgAggregate := OrgIamPolicyRemovedAggregate(es.Eventstore.AggregateCreator(), repoOrg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregate)
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ func GetMockedEventstoreComplexity(ctrl *gomock.Controller, mockEs *mock.MockEve
|
||||
|
||||
func GetMockChangesOrgOK(ctrl *gomock.Controller) *OrgEventstore {
|
||||
org := model.Org{
|
||||
Name: "MusterOrg",
|
||||
Domain: "myDomain",
|
||||
Name: "MusterOrg",
|
||||
}
|
||||
data, err := json.Marshal(org)
|
||||
if err != nil {
|
||||
|
@ -1058,7 +1058,7 @@ func TestChangesOrg(t *testing.T) {
|
||||
},
|
||||
res: res{
|
||||
changes: &org_model.OrgChanges{Changes: []*org_model.OrgChange{&org_model.OrgChange{EventType: "", Sequence: 1, Modifier: ""}}, LastSequence: 1},
|
||||
org: &model.Org{Name: "MusterOrg", Domain: "myDomain"},
|
||||
org: &model.Org{Name: "MusterOrg"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
120
internal/org/repository/eventsourcing/model/domain.go
Normal file
120
internal/org/repository/eventsourcing/model/domain.go
Normal file
@ -0,0 +1,120 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/model"
|
||||
)
|
||||
|
||||
type OrgDomain struct {
|
||||
es_models.ObjectRoot `json:"-"`
|
||||
|
||||
Domain string `json:"domain"`
|
||||
Verified bool `json:"-"`
|
||||
Primary bool `json:"-"`
|
||||
}
|
||||
|
||||
func GetDomain(domains []*OrgDomain, domain string) (int, *OrgDomain) {
|
||||
for i, d := range domains {
|
||||
if d.Domain == domain {
|
||||
return i, d
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (o *Org) appendAddDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain.ObjectRoot.CreationDate = event.CreationDate
|
||||
o.Domains = append(o.Domains, domain)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendRemoveDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, r := GetDomain(o.Domains, domain.Domain); r != nil {
|
||||
o.Domains[i] = o.Domains[len(o.Domains)-1]
|
||||
o.Domains[len(o.Domains)-1] = nil
|
||||
o.Domains = o.Domains[:len(o.Domains)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendVerifyDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, d := GetDomain(o.Domains, domain.Domain); d != nil {
|
||||
d.Verified = true
|
||||
o.Domains[i] = d
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendPrimaryDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, d := range o.Domains {
|
||||
d.Primary = false
|
||||
if d.Domain == domain.Domain {
|
||||
d.Primary = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OrgDomain) SetData(event *es_models.Event) error {
|
||||
err := json.Unmarshal(event.Data, m)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func OrgDomainsFromModel(domains []*model.OrgDomain) []*OrgDomain {
|
||||
convertedDomainss := make([]*OrgDomain, len(domains))
|
||||
for i, m := range domains {
|
||||
convertedDomainss[i] = OrgDomainFromModel(m)
|
||||
}
|
||||
return convertedDomainss
|
||||
}
|
||||
|
||||
func OrgDomainFromModel(domain *model.OrgDomain) *OrgDomain {
|
||||
return &OrgDomain{
|
||||
ObjectRoot: domain.ObjectRoot,
|
||||
Domain: domain.Domain,
|
||||
Verified: domain.Verified,
|
||||
Primary: domain.Primary,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainsToModel(domains []*OrgDomain) []*model.OrgDomain {
|
||||
convertedDomains := make([]*model.OrgDomain, len(domains))
|
||||
for i, m := range domains {
|
||||
convertedDomains[i] = OrgDomainToModel(m)
|
||||
}
|
||||
return convertedDomains
|
||||
}
|
||||
|
||||
func OrgDomainToModel(domain *OrgDomain) *model.OrgDomain {
|
||||
return &model.OrgDomain{
|
||||
ObjectRoot: domain.ObjectRoot,
|
||||
Domain: domain.Domain,
|
||||
Verified: domain.Verified,
|
||||
Primary: domain.Primary,
|
||||
}
|
||||
}
|
@ -14,33 +14,42 @@ const (
|
||||
type Org struct {
|
||||
es_models.ObjectRoot `json:"-"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
|
||||
Members []*OrgMember `json:"-"`
|
||||
Domains []*OrgDomain `json:"-"`
|
||||
Members []*OrgMember `json:"-"`
|
||||
OrgIamPolicy *OrgIamPolicy `json:"-"`
|
||||
}
|
||||
|
||||
func OrgFromModel(org *org_model.Org) *Org {
|
||||
members := OrgMembersFromModel(org.Members)
|
||||
|
||||
return &Org{
|
||||
domains := OrgDomainsFromModel(org.Domains)
|
||||
converted := &Org{
|
||||
ObjectRoot: org.ObjectRoot,
|
||||
Domain: org.Domain,
|
||||
Name: org.Name,
|
||||
State: int32(org.State),
|
||||
Domains: domains,
|
||||
Members: members,
|
||||
}
|
||||
if org.OrgIamPolicy != nil {
|
||||
converted.OrgIamPolicy = OrgIamPolicyFromModel(org.OrgIamPolicy)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func OrgToModel(org *Org) *org_model.Org {
|
||||
return &org_model.Org{
|
||||
converted := &org_model.Org{
|
||||
ObjectRoot: org.ObjectRoot,
|
||||
Domain: org.Domain,
|
||||
Name: org.Name,
|
||||
State: org_model.OrgState(org.State),
|
||||
Domains: OrgDomainsToModel(org.Domains),
|
||||
Members: OrgMembersToModel(org.Members),
|
||||
}
|
||||
if org.OrgIamPolicy != nil {
|
||||
converted.OrgIamPolicy = OrgIamPolicyToModel(org.OrgIamPolicy)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func OrgFromEvents(org *Org, events ...*es_models.Event) (*Org, error) {
|
||||
@ -101,6 +110,20 @@ func (o *Org) AppendEvent(event *es_models.Event) error {
|
||||
return err
|
||||
}
|
||||
o.removeMember(member.UserID)
|
||||
case OrgDomainAdded:
|
||||
o.appendAddDomainEvent(event)
|
||||
case OrgDomainVerified:
|
||||
o.appendVerifyDomainEvent(event)
|
||||
case OrgDomainPrimarySet:
|
||||
o.appendPrimaryDomainEvent(event)
|
||||
case OrgDomainRemoved:
|
||||
o.appendRemoveDomainEvent(event)
|
||||
case OrgIamPolicyAdded:
|
||||
o.appendAddOrgIamPolicyEvent(event)
|
||||
case OrgIamPolicyChanged:
|
||||
o.appendChangeOrgIamPolicyEvent(event)
|
||||
case OrgIamPolicyRemoved:
|
||||
o.appendRemoveOrgIamPolicyEvent()
|
||||
}
|
||||
|
||||
o.ObjectRoot.AppendEvent(event)
|
||||
@ -151,9 +174,6 @@ func (o *Org) Changes(changed *Org) map[string]interface{} {
|
||||
if changed.Name != "" && changed.Name != o.Name {
|
||||
changes["name"] = changed.Name
|
||||
}
|
||||
if changed.Domain != "" && changed.Domain != o.Domain {
|
||||
changes["domain"] = changed.Domain
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
)
|
||||
|
||||
type OrgIamPolicy struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Description string `json:"description,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
UserLoginMustBeDomain bool `json:"userLoginMustBeDomain"`
|
||||
}
|
||||
|
||||
func OrgIamPolicyToModel(policy *OrgIamPolicy) *org_model.OrgIamPolicy {
|
||||
return &org_model.OrgIamPolicy{
|
||||
ObjectRoot: policy.ObjectRoot,
|
||||
State: org_model.PolicyState(policy.State),
|
||||
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgIamPolicyFromModel(policy *org_model.OrgIamPolicy) *OrgIamPolicy {
|
||||
return &OrgIamPolicy{
|
||||
ObjectRoot: policy.ObjectRoot,
|
||||
State: int32(policy.State),
|
||||
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Org) appendAddOrgIamPolicyEvent(event *es_models.Event) error {
|
||||
o.OrgIamPolicy = new(OrgIamPolicy)
|
||||
err := o.OrgIamPolicy.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.OrgIamPolicy.ObjectRoot.CreationDate = event.CreationDate
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendChangeOrgIamPolicyEvent(event *es_models.Event) error {
|
||||
return o.OrgIamPolicy.SetData(event)
|
||||
}
|
||||
|
||||
func (o *Org) appendRemoveOrgIamPolicyEvent() {
|
||||
o.OrgIamPolicy = nil
|
||||
}
|
||||
|
||||
func (p *OrgIamPolicy) Changes(changed *OrgIamPolicy) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 2)
|
||||
|
||||
if changed.Description != p.Description {
|
||||
changes["description"] = changed.Description
|
||||
}
|
||||
if changed.UserLoginMustBeDomain != p.UserLoginMustBeDomain {
|
||||
changes["userLoginMustBeDomain"] = changed.UserLoginMustBeDomain
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
func (p *OrgIamPolicy) SetData(event *es_models.Event) error {
|
||||
err := json.Unmarshal(event.Data, p)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "EVENT-7JS9d", "unable to unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -74,10 +74,10 @@ func TestAppendEvent(t *testing.T) {
|
||||
{
|
||||
name: "append change event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)},
|
||||
org: &Org{Name: "OrgName", Domain: "asdf"},
|
||||
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"name": "OrgName}`)},
|
||||
org: &Org{Name: "OrgNameChanged"},
|
||||
},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName", Domain: "OrgDomain"},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgNameChanged"},
|
||||
},
|
||||
{
|
||||
name: "append deactivate event",
|
||||
@ -93,6 +93,13 @@ func TestAppendEvent(t *testing.T) {
|
||||
},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
|
||||
},
|
||||
{
|
||||
name: "append added domain event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgDomainAdded},
|
||||
},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@ -138,16 +145,6 @@ func TestChanges(t *testing.T) {
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org domain changes",
|
||||
args: args{
|
||||
existing: &Org{Name: "Name", Domain: "old domain"},
|
||||
new: &Org{Name: "Name", Domain: "new domain"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
@ -7,11 +7,15 @@ const (
|
||||
OrgDomainAggregate models.AggregateType = "org.domain"
|
||||
OrgNameAggregate models.AggregateType = "org.name"
|
||||
|
||||
OrgAdded models.EventType = "org.added"
|
||||
OrgChanged models.EventType = "org.changed"
|
||||
OrgDeactivated models.EventType = "org.deactivated"
|
||||
OrgReactivated models.EventType = "org.reactivated"
|
||||
OrgRemoved models.EventType = "org.removed"
|
||||
OrgAdded models.EventType = "org.added"
|
||||
OrgChanged models.EventType = "org.changed"
|
||||
OrgDeactivated models.EventType = "org.deactivated"
|
||||
OrgReactivated models.EventType = "org.reactivated"
|
||||
OrgRemoved models.EventType = "org.removed"
|
||||
OrgDomainAdded models.EventType = "org.domain.added"
|
||||
OrgDomainVerified models.EventType = "org.domain.verified"
|
||||
OrgDomainRemoved models.EventType = "org.domain.removed"
|
||||
OrgDomainPrimarySet models.EventType = "org.domain.primary.set"
|
||||
|
||||
OrgNameReserved models.EventType = "org.name.reserved"
|
||||
OrgNameReleased models.EventType = "org.name.released"
|
||||
@ -22,4 +26,8 @@ const (
|
||||
OrgMemberAdded models.EventType = "org.member.added"
|
||||
OrgMemberChanged models.EventType = "org.member.changed"
|
||||
OrgMemberRemoved models.EventType = "org.member.removed"
|
||||
|
||||
OrgIamPolicyAdded models.EventType = "org.iam.policy.added"
|
||||
OrgIamPolicyChanged models.EventType = "org.iam.policy.changed"
|
||||
OrgIamPolicyRemoved models.EventType = "org.iam.policy.removed"
|
||||
)
|
||||
|
@ -47,16 +47,6 @@ 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.AggregateID, org.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, org.AggregateID, org.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, model.OrgAggregate, model.OrgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -65,12 +55,44 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0)
|
||||
aggregates, err = addDomainAggregateAndEvents(ctx, aggCreator, agg, aggregates, org)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameAggregate, err := reservedUniqueNameAggregate(ctx, aggCreator, org.AggregateID, org.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, nameAggregate)
|
||||
return append(aggregates, agg), nil
|
||||
}
|
||||
|
||||
return []*es_models.Aggregate{
|
||||
agg,
|
||||
domainAgrregate,
|
||||
nameAggregate,
|
||||
}, nil
|
||||
func addDomainAggregateAndEvents(ctx context.Context, aggCreator *es_models.AggregateCreator, orgAggregate *es_models.Aggregate, aggregates []*es_models.Aggregate, org *model.Org) ([]*es_models.Aggregate, error) {
|
||||
for _, domain := range org.Domains {
|
||||
orgAggregate, err := orgAggregate.AppendEvent(model.OrgDomainAdded, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain.Verified {
|
||||
domainAggregate, err := reservedUniqueDomainAggregate(ctx, aggCreator, org.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAggregate)
|
||||
orgAggregate, err = orgAggregate.AppendEvent(model.OrgDomainVerified, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if domain.Primary {
|
||||
orgAggregate, err = orgAggregate.AppendEvent(model.OrgDomainPrimarySet, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return aggregates, nil
|
||||
}
|
||||
|
||||
func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, updated *model.Org) ([]*es_models.Aggregate, error) {
|
||||
@ -88,19 +110,16 @@ 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 := reservedUniqueNameAggregate(ctx, aggCreator, "", name.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, nameAggregate)
|
||||
}
|
||||
|
||||
if name, ok := changes["domain"]; ok {
|
||||
domainAggregate, err := uniqueDomainAggregate(ctx, aggCreator, "", name.(string))
|
||||
nameReleasedAggregate, err := releasedUniqueNameAggregate(ctx, aggCreator, "", existing.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAggregate)
|
||||
aggregates = append(aggregates, nameReleasedAggregate)
|
||||
}
|
||||
|
||||
orgAggregate, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
@ -151,7 +170,7 @@ func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *model.O
|
||||
}
|
||||
}
|
||||
|
||||
func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
|
||||
func reservedUniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
@ -164,10 +183,26 @@ func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateC
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, model.OrgDomainReserved)), nil
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isEventValidation(aggregate, model.OrgDomainReserved)), nil
|
||||
}
|
||||
|
||||
func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
|
||||
func releasedUniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregate, err = aggregate.AppendEvent(model.OrgDomainReleased, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isEventValidation(aggregate, model.OrgDomainReleased)), nil
|
||||
}
|
||||
|
||||
func reservedUniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
@ -180,17 +215,103 @@ func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, model.OrgNameReserved)), nil
|
||||
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isEventValidation(aggregate, model.OrgNameReserved)), nil
|
||||
}
|
||||
|
||||
func isReservedValidation(aggregate *es_models.Aggregate, resevedEventType es_models.EventType) func(...*es_models.Event) error {
|
||||
func releasedUniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregate, err = aggregate.AppendEvent(model.OrgNameReleased, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isEventValidation(aggregate, model.OrgNameReleased)), nil
|
||||
}
|
||||
|
||||
func OrgDomainAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-OSid3", "domain should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgDomainAdded, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-DHs7s", "domain should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0, 2)
|
||||
agg, err = agg.AppendEvent(model.OrgDomainVerified, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainAgregate, err := reservedUniqueDomainAggregate(ctx, aggCreator, existing.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAgregate)
|
||||
return append(aggregates, agg), nil
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainSetPrimaryAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-PSw3j", "domain should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgDomainPrimarySet, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) ([]*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-si8dW", "domain should not be nil")
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0, 2)
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.OrgDomainRemoved, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, agg)
|
||||
domainAgregate, err := releasedUniqueDomainAggregate(ctx, aggCreator, existing.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(aggregates, domainAgregate), nil
|
||||
}
|
||||
|
||||
func isEventValidation(aggregate *es_models.Aggregate, eventType es_models.EventType) func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
if len(events) == 0 {
|
||||
aggregate.PreviousSequence = 0
|
||||
return nil
|
||||
}
|
||||
if events[0].Type == resevedEventType {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-eJQqe", "org already reseved")
|
||||
if events[0].Type == eventType {
|
||||
return errors.ThrowPreconditionFailedf(nil, "EVENT-eJQqe", "user is already %v", eventType)
|
||||
}
|
||||
aggregate.PreviousSequence = events[0].Sequence
|
||||
return nil
|
||||
|
48
internal/org/repository/eventsourcing/org_iam_policy.go
Normal file
48
internal/org/repository/eventsourcing/org_iam_policy.go
Normal file
@ -0,0 +1,48 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func OrgIamPolicyAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, policy *model.OrgIamPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if policy == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-i9sJS", "policy should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgIamPolicyAdded, policy)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgIamPolicyChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, policy *model.OrgIamPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if policy == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9Ksie", "policy should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := existing.OrgIamPolicy.Changes(policy)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Js6Vs", "no changes")
|
||||
}
|
||||
return agg.AppendEvent(model.OrgIamPolicyChanged, changes)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgIamPolicyRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgIamPolicyRemoved, nil)
|
||||
}
|
||||
}
|
237
internal/org/repository/eventsourcing/org_iam_policy_test.go
Normal file
237
internal/org/repository/eventsourcing/org_iam_policy_test.go
Normal file
@ -0,0 +1,237 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOrgIamPolicyAddedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
policy *model.OrgIamPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no policy error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
policy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgIamPolicyAdded,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgIamPolicyAddedAggregate(tt.args.aggCreator, tt.args.org, tt.args.policy)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgIamPolicyAddedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgIamPolicyAddedAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgIamPolicyChangedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
policy *model.OrgIamPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no policy error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
OrgIamPolicy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
policy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgIamPolicyChanged,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy no changes",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
OrgIamPolicy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
policy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgIamPolicyChangedAggregate(tt.args.aggCreator, tt.args.org, tt.args.policy)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgIamPolicyRemovedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "policy successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
OrgIamPolicy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgIamPolicyRemoved,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgIamPolicyRemovedAggregate(tt.args.aggCreator, tt.args.org)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -79,7 +79,7 @@ func Test_isReservedValidation(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
validate := isReservedValidation(tt.args.aggregate, tt.args.eventType)
|
||||
validate := isEventValidation(tt.args.aggregate, tt.args.eventType)
|
||||
|
||||
err := validate(tt.args.Events...)
|
||||
|
||||
@ -142,7 +142,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 := reservedUniqueNameAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgName)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got: %v", err)
|
||||
}
|
||||
@ -198,7 +198,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 := reservedUniqueDomainAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgDomain)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got: %v", err)
|
||||
}
|
||||
@ -425,47 +425,18 @@ func TestOrgUpdateAggregates(t *testing.T) {
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "coas",
|
||||
Name: "coas",
|
||||
},
|
||||
updated: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "caos",
|
||||
Name: "caos",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain changed",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
existing: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.swiss",
|
||||
Name: "caos",
|
||||
},
|
||||
updated: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "caos",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
aggregateCount: 3,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
@ -523,17 +494,16 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "caos",
|
||||
Name: "caos",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 3,
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no domain error",
|
||||
name: "org with domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
@ -543,11 +513,14 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
Sequence: 5,
|
||||
},
|
||||
Name: "caos",
|
||||
Domains: []*model.OrgDomain{&model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
}},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -560,7 +533,6 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -584,3 +556,270 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainAddedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventCount: 1,
|
||||
eventType: model.OrgDomainAdded,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgDomainAddedAggregate(tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgDomainAddedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventCount {
|
||||
t.Errorf("OrgDomainAddedAggregate() event count = %v, wanted count %v", len(got.Events), tt.res.eventCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainVerifiedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
aggregateCount int
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgDomainVerifiedAggregate(tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got) != tt.res.aggregateCount {
|
||||
t.Errorf("OrgDomainVerifiedAggregate() aggregate count = %d, wanted count %d", len(got), tt.res.aggregateCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainSetPrimaryAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgDomainPrimarySet,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgDomainSetPrimaryAggregate(tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgDomainSetPrimaryAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgDomainSetPrimaryAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainRemovedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
aggregateCount int
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 0,
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := OrgDomainRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got) != tt.res.aggregateCount {
|
||||
t.Errorf("OrgDomainRemovedAggregate() aggregate count = %d, wanted count %d", len(got), tt.res.aggregateCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package view
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -33,7 +33,6 @@ type OrgView struct {
|
||||
|
||||
func OrgFromModel(org *org_model.OrgView) *OrgView {
|
||||
return &OrgView{
|
||||
Domain: org.Domain,
|
||||
ChangeDate: org.ChangeDate,
|
||||
CreationDate: org.CreationDate,
|
||||
ID: org.ID,
|
||||
@ -46,7 +45,6 @@ func OrgFromModel(org *org_model.OrgView) *OrgView {
|
||||
|
||||
func OrgToModel(org *OrgView) *org_model.OrgView {
|
||||
return &org_model.OrgView{
|
||||
Domain: org.Domain,
|
||||
ChangeDate: org.ChangeDate,
|
||||
CreationDate: org.CreationDate,
|
||||
ID: org.ID,
|
87
internal/org/repository/view/model/org_domain.go
Normal file
87
internal/org/repository/view/model/org_domain.go
Normal file
@ -0,0 +1,87 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/model"
|
||||
es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
OrgDomainKeyOrgID = "org_id"
|
||||
OrgDomainKeyDomain = "domain"
|
||||
OrgDomainKeyVerified = "verified"
|
||||
OrgDomainKeyPrimary = "primary_domain"
|
||||
)
|
||||
|
||||
type OrgDomainView struct {
|
||||
Domain string `json:"domain" gorm:"column:domain;primary_key"`
|
||||
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
|
||||
Verified bool `json:"-" gorm:"column:verified"`
|
||||
Primary bool `json:"-" gorm:"column:primary_domain"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
}
|
||||
|
||||
func OrgDomainViewFromModel(domain *model.OrgDomainView) *OrgDomainView {
|
||||
return &OrgDomainView{
|
||||
OrgID: domain.OrgID,
|
||||
Domain: domain.Domain,
|
||||
Primary: domain.Primary,
|
||||
Verified: domain.Verified,
|
||||
CreationDate: domain.CreationDate,
|
||||
ChangeDate: domain.ChangeDate,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainToModel(domain *OrgDomainView) *model.OrgDomainView {
|
||||
return &model.OrgDomainView{
|
||||
OrgID: domain.OrgID,
|
||||
Domain: domain.Domain,
|
||||
Primary: domain.Primary,
|
||||
Verified: domain.Verified,
|
||||
CreationDate: domain.CreationDate,
|
||||
ChangeDate: domain.ChangeDate,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainsToModel(domain []*OrgDomainView) []*model.OrgDomainView {
|
||||
result := make([]*model.OrgDomainView, len(domain))
|
||||
for i, r := range domain {
|
||||
result[i] = OrgDomainToModel(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *OrgDomainView) AppendEvent(event *models.Event) (err error) {
|
||||
d.Sequence = event.Sequence
|
||||
d.ChangeDate = event.CreationDate
|
||||
switch event.Type {
|
||||
case es_model.OrgDomainAdded:
|
||||
d.setRootData(event)
|
||||
d.CreationDate = event.CreationDate
|
||||
err = d.SetData(event)
|
||||
case es_model.OrgDomainVerified:
|
||||
d.Verified = true
|
||||
case es_model.OrgDomainPrimarySet:
|
||||
d.Primary = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *OrgDomainView) setRootData(event *models.Event) {
|
||||
r.OrgID = event.AggregateID
|
||||
}
|
||||
|
||||
func (r *OrgDomainView) SetData(event *models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||
logging.Log("EVEN-sj4Sf").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
65
internal/org/repository/view/model/org_domain_query.go
Normal file
65
internal/org/repository/view/model/org_domain_query.go
Normal file
@ -0,0 +1,65 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
)
|
||||
|
||||
type OrgDomainSearchRequest org_model.OrgDomainSearchRequest
|
||||
type OrgDomainSearchQuery org_model.OrgDomainSearchQuery
|
||||
type OrgDomainSearchKey org_model.OrgDomainSearchKey
|
||||
|
||||
func (req OrgDomainSearchRequest) GetLimit() uint64 {
|
||||
return req.Limit
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchRequest) GetOffset() uint64 {
|
||||
return req.Offset
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchRequest) GetSortingColumn() view.ColumnKey {
|
||||
if req.SortingColumn == org_model.ORGDOMAINSEARCHKEY_UNSPECIFIED {
|
||||
return nil
|
||||
}
|
||||
return OrgDomainSearchKey(req.SortingColumn)
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchRequest) GetAsc() bool {
|
||||
return req.Asc
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchRequest) GetQueries() []view.SearchQuery {
|
||||
result := make([]view.SearchQuery, len(req.Queries))
|
||||
for i, q := range req.Queries {
|
||||
result[i] = OrgDomainSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchQuery) GetKey() view.ColumnKey {
|
||||
return OrgDomainSearchKey(req.Key)
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchQuery) GetMethod() global_model.SearchMethod {
|
||||
return req.Method
|
||||
}
|
||||
|
||||
func (req OrgDomainSearchQuery) GetValue() interface{} {
|
||||
return req.Value
|
||||
}
|
||||
|
||||
func (key OrgDomainSearchKey) ToColumnName() string {
|
||||
switch org_model.OrgDomainSearchKey(key) {
|
||||
case org_model.ORGDOMAINSEARCHKEY_DOMAIN:
|
||||
return OrgDomainKeyDomain
|
||||
case org_model.ORGDOMAINSEARCHKEY_ORG_ID:
|
||||
return OrgDomainKeyOrgID
|
||||
case org_model.ORGDOMAINSEARCHKEY_VERIFIED:
|
||||
return OrgDomainKeyVerified
|
||||
case org_model.ORGDOMAINSEARCHKEY_PRIMARY:
|
||||
return OrgDomainKeyPrimary
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package view
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
@ -1,4 +1,4 @@
|
||||
package view
|
||||
package model
|
||||
|
||||
import (
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
@ -1,4 +1,4 @@
|
||||
package view
|
||||
package model
|
||||
|
||||
import (
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
64
internal/org/repository/view/org_domain_view.go
Normal file
64
internal/org/repository/view/org_domain_view.go
Normal file
@ -0,0 +1,64 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
func OrgDomainByOrgIDAndDomain(db *gorm.DB, table, orgID, domain string) (*model.OrgDomainView, error) {
|
||||
domainView := new(model.OrgDomainView)
|
||||
orgIDQuery := &model.OrgDomainSearchQuery{Key: org_model.ORGDOMAINSEARCHKEY_ORG_ID, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
domainQuery := &model.OrgDomainSearchQuery{Key: org_model.ORGDOMAINSEARCHKEY_DOMAIN, Value: domain, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
query := view.PrepareGetByQuery(table, orgIDQuery, domainQuery)
|
||||
err := query(db, domainView)
|
||||
return domainView, err
|
||||
}
|
||||
|
||||
func VerifiedOrgDomain(db *gorm.DB, table, domain string) (*model.OrgDomainView, error) {
|
||||
domainView := new(model.OrgDomainView)
|
||||
domainQuery := &model.OrgDomainSearchQuery{Key: org_model.ORGDOMAINSEARCHKEY_DOMAIN, Value: domain, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
verifiedQuery := &model.OrgDomainSearchQuery{Key: org_model.ORGDOMAINSEARCHKEY_VERIFIED, Value: true, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
query := view.PrepareGetByQuery(table, domainQuery, verifiedQuery)
|
||||
err := query(db, domainView)
|
||||
return domainView, err
|
||||
}
|
||||
|
||||
func SearchOrgDomains(db *gorm.DB, table string, req *org_model.OrgDomainSearchRequest) ([]*model.OrgDomainView, int, error) {
|
||||
members := make([]*model.OrgDomainView, 0)
|
||||
query := view.PrepareSearchQuery(table, model.OrgDomainSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
count, err := query(db, &members)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return members, count, nil
|
||||
}
|
||||
|
||||
func OrgDomainsByOrgID(db *gorm.DB, table string, orgID string) ([]*model.OrgDomainView, error) {
|
||||
domains := make([]*model.OrgDomainView, 0)
|
||||
queries := []*org_model.OrgDomainSearchQuery{
|
||||
{
|
||||
Key: org_model.ORGDOMAINSEARCHKEY_ORG_ID,
|
||||
Value: orgID,
|
||||
Method: global_model.SEARCHMETHOD_EQUALS,
|
||||
},
|
||||
}
|
||||
query := view.PrepareSearchQuery(table, model.OrgDomainSearchRequest{Queries: queries})
|
||||
_, err := query(db, &domains)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
func PutOrgDomain(db *gorm.DB, table string, role *model.OrgDomainView) error {
|
||||
save := view.PrepareSave(table)
|
||||
return save(db, role)
|
||||
}
|
||||
|
||||
func DeleteOrgDomain(db *gorm.DB, table, domain string) error {
|
||||
delete := view.PrepareDeleteByKey(table, model.OrgSearchKey(org_model.ORGDOMAINSEARCHKEY_DOMAIN), domain)
|
||||
return delete(db)
|
||||
}
|
@ -3,31 +3,32 @@ package view
|
||||
import (
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
func OrgMemberByIDs(db *gorm.DB, table, orgID, userID string) (*OrgMemberView, error) {
|
||||
member := new(OrgMemberView)
|
||||
func OrgMemberByIDs(db *gorm.DB, table, orgID, userID string) (*model.OrgMemberView, error) {
|
||||
member := new(model.OrgMemberView)
|
||||
|
||||
orgIDQuery := &OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_ORG_ID, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
userIDQuery := &OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_USER_ID, Value: userID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
orgIDQuery := &model.OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_ORG_ID, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
userIDQuery := &model.OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_USER_ID, Value: userID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||
query := view.PrepareGetByQuery(table, orgIDQuery, userIDQuery)
|
||||
err := query(db, member)
|
||||
return member, err
|
||||
}
|
||||
|
||||
func SearchOrgMembers(db *gorm.DB, table string, req *org_model.OrgMemberSearchRequest) ([]*OrgMemberView, int, error) {
|
||||
members := make([]*OrgMemberView, 0)
|
||||
query := view.PrepareSearchQuery(table, OrgMemberSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
func SearchOrgMembers(db *gorm.DB, table string, req *org_model.OrgMemberSearchRequest) ([]*model.OrgMemberView, int, error) {
|
||||
members := make([]*model.OrgMemberView, 0)
|
||||
query := view.PrepareSearchQuery(table, model.OrgMemberSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
count, err := query(db, &members)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return members, count, nil
|
||||
}
|
||||
func OrgMembersByUserID(db *gorm.DB, table string, userID string) ([]*OrgMemberView, error) {
|
||||
members := make([]*OrgMemberView, 0)
|
||||
func OrgMembersByUserID(db *gorm.DB, table string, userID string) ([]*model.OrgMemberView, error) {
|
||||
members := make([]*model.OrgMemberView, 0)
|
||||
queries := []*org_model.OrgMemberSearchQuery{
|
||||
{
|
||||
Key: org_model.ORGMEMBERSEARCHKEY_USER_ID,
|
||||
@ -35,7 +36,7 @@ func OrgMembersByUserID(db *gorm.DB, table string, userID string) ([]*OrgMemberV
|
||||
Method: global_model.SEARCHMETHOD_EQUALS,
|
||||
},
|
||||
}
|
||||
query := view.PrepareSearchQuery(table, OrgMemberSearchRequest{Queries: queries})
|
||||
query := view.PrepareSearchQuery(table, model.OrgMemberSearchRequest{Queries: queries})
|
||||
_, err := query(db, &members)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -43,7 +44,7 @@ func OrgMembersByUserID(db *gorm.DB, table string, userID string) ([]*OrgMemberV
|
||||
return members, nil
|
||||
}
|
||||
|
||||
func PutOrgMember(db *gorm.DB, table string, role *OrgMemberView) error {
|
||||
func PutOrgMember(db *gorm.DB, table string, role *model.OrgMemberView) error {
|
||||
save := view.PrepareSave(table)
|
||||
return save(db, role)
|
||||
}
|
||||
|
@ -2,20 +2,21 @@ package view
|
||||
|
||||
import (
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
func OrgByID(db *gorm.DB, table, orgID string) (*OrgView, error) {
|
||||
org := new(OrgView)
|
||||
query := view.PrepareGetByKey(table, OrgSearchKey(org_model.ORGSEARCHKEY_ORG_ID), orgID)
|
||||
func OrgByID(db *gorm.DB, table, orgID string) (*model.OrgView, error) {
|
||||
org := new(model.OrgView)
|
||||
query := view.PrepareGetByKey(table, model.OrgSearchKey(org_model.ORGSEARCHKEY_ORG_ID), orgID)
|
||||
err := query(db, org)
|
||||
return org, err
|
||||
}
|
||||
|
||||
func SearchOrgs(db *gorm.DB, table string, req *org_model.OrgSearchRequest) ([]*OrgView, int, error) {
|
||||
orgs := make([]*OrgView, 0)
|
||||
query := view.PrepareSearchQuery(table, OrgSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
func SearchOrgs(db *gorm.DB, table string, req *org_model.OrgSearchRequest) ([]*model.OrgView, int, error) {
|
||||
orgs := make([]*model.OrgView, 0)
|
||||
query := view.PrepareSearchQuery(table, model.OrgSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
count, err := query(db, &orgs)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
@ -23,19 +24,12 @@ func SearchOrgs(db *gorm.DB, table string, req *org_model.OrgSearchRequest) ([]*
|
||||
return orgs, count, nil
|
||||
}
|
||||
|
||||
func GetGlobalOrgByDomain(db *gorm.DB, table, domain string) (*OrgView, error) {
|
||||
org := new(OrgView)
|
||||
query := view.PrepareGetByKey(table, OrgSearchKey(org_model.ORGSEARCHKEY_ORG_DOMAIN), domain)
|
||||
err := query(db, org)
|
||||
return org, err
|
||||
}
|
||||
|
||||
func PutOrg(db *gorm.DB, table string, org *OrgView) error {
|
||||
func PutOrg(db *gorm.DB, table string, org *model.OrgView) error {
|
||||
save := view.PrepareSave(table)
|
||||
return save(db, org)
|
||||
}
|
||||
|
||||
func DeleteOrg(db *gorm.DB, table, orgID string) error {
|
||||
delete := view.PrepareDeleteByKey(table, OrgSearchKey(org_model.ORGSEARCHKEY_ORG_ID), orgID)
|
||||
delete := view.PrepareDeleteByKey(table, model.OrgSearchKey(org_model.ORGSEARCHKEY_ORG_ID), orgID)
|
||||
return delete(db)
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ func PasswordAgePolicyQuery(recourceOwner string, latestSequence uint64) *es_mod
|
||||
AggregateTypeFilter(model.PasswordAgePolicyAggregate).
|
||||
LatestSequenceFilter(latestSequence).
|
||||
ResourceOwnerFilter(recourceOwner)
|
||||
|
||||
}
|
||||
|
||||
func PasswordAgePolicyAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, policy *PasswordAgePolicy) (*es_models.Aggregate, error) {
|
||||
|
@ -46,7 +46,7 @@ const (
|
||||
type ApplicationSearchQuery struct {
|
||||
Key ApplicationSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type ApplicationSearchResponse struct {
|
||||
|
@ -42,7 +42,7 @@ const (
|
||||
type ProjectGrantMemberSearchQuery struct {
|
||||
Key ProjectGrantMemberSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type ProjectGrantMemberSearchResponse struct {
|
||||
|
@ -41,7 +41,7 @@ const (
|
||||
type ProjectMemberSearchQuery struct {
|
||||
Key ProjectMemberSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type ProjectMemberSearchResponse struct {
|
||||
|
@ -38,7 +38,7 @@ const (
|
||||
type ProjectRoleSearchQuery struct {
|
||||
Key ProjectRoleSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type ProjectRoleSearchResponse struct {
|
||||
|
@ -29,7 +29,6 @@ type ProjectGrantView struct {
|
||||
State int32 `json:"-" gorm:"column:project_state"`
|
||||
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||
OrgName string `json:"-" gorm:"column:org_name"`
|
||||
OrgDomain string `json:"-" gorm:"column:org_domain"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
GrantedRoleKeys pq.StringArray `json:"-" gorm:"column:granted_role_keys"`
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
policy_model "github.com/caos/zitadel/internal/policy/model"
|
||||
"strings"
|
||||
"time"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
@ -66,10 +68,17 @@ const (
|
||||
GENDER_DIVERSE
|
||||
)
|
||||
|
||||
func (u *User) SetEmailAsUsername() {
|
||||
if u.Profile != nil && u.UserName == "" && u.Email != nil {
|
||||
func (u *User) CheckOrgIamPolicy(policy *org_model.OrgIamPolicy) error {
|
||||
if policy == nil {
|
||||
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Org Iam Policy should not be nil")
|
||||
}
|
||||
if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") {
|
||||
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Username should not be email address")
|
||||
}
|
||||
if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil {
|
||||
u.UserName = u.EmailAddress
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) IsValid() bool {
|
||||
|
@ -44,7 +44,7 @@ const (
|
||||
type UserSessionSearchQuery struct {
|
||||
Key UserSessionSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type UserSessionSearchResponse struct {
|
||||
|
@ -18,6 +18,7 @@ type UserView struct {
|
||||
PasswordChanged time.Time
|
||||
LastLogin time.Time
|
||||
UserName string
|
||||
LoginNames []string
|
||||
FirstName string
|
||||
LastName string
|
||||
NickName string
|
||||
@ -61,12 +62,13 @@ const (
|
||||
USERSEARCHKEY_EMAIL
|
||||
USERSEARCHKEY_STATE
|
||||
USERSEARCHKEY_RESOURCEOWNER
|
||||
USERSEARCHKEY_LOGIN_NAMES
|
||||
)
|
||||
|
||||
type UserSearchQuery struct {
|
||||
Key UserSearchKey
|
||||
Method model.SearchMethod
|
||||
Value string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type UserSearchResponse struct {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
policy_model "github.com/caos/zitadel/internal/policy/model"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
|
||||
@ -103,8 +104,8 @@ func (es *UserEventstore) UserEventsByID(ctx context.Context, id string, sequenc
|
||||
return es.FilterEvents(ctx, query)
|
||||
}
|
||||
|
||||
func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
|
||||
user.SetEmailAsUsername()
|
||||
func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, pwPolicy *policy_model.PasswordComplexityPolicy, orgIamPolicy *org_model.OrgIamPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
|
||||
err := user.CheckOrgIamPolicy(orgIamPolicy)
|
||||
if !user.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "User is invalid")
|
||||
}
|
||||
@ -115,7 +116,7 @@ func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model
|
||||
}
|
||||
user.AggregateID = id
|
||||
|
||||
err = user.HashPasswordIfExisting(policy, es.PasswordAlg, true)
|
||||
err = user.HashPasswordIfExisting(pwPolicy, es.PasswordAlg, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -132,13 +133,13 @@ func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model
|
||||
repoInitCode := model.InitCodeFromModel(user.InitCode)
|
||||
repoPhoneCode := model.PhoneCodeFromModel(user.PhoneCode)
|
||||
|
||||
createAggregates, err := UserCreateAggregate(ctx, es.AggregateCreator(), repoUser, repoInitCode, repoPhoneCode, resourceOwner)
|
||||
createAggregates, err := UserCreateAggregate(ctx, es.AggregateCreator(), repoUser, repoInitCode, repoPhoneCode, resourceOwner, orgIamPolicy.UserLoginMustBeDomain)
|
||||
|
||||
return repoUser, createAggregates, err
|
||||
}
|
||||
|
||||
func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy) (*usr_model.User, error) {
|
||||
repoUser, aggregates, err := es.PrepareCreateUser(ctx, user, policy, "")
|
||||
func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User, pwPolicy *policy_model.PasswordComplexityPolicy, orgIamPolicy *org_model.OrgIamPolicy) (*usr_model.User, error) {
|
||||
repoUser, aggregates, err := es.PrepareCreateUser(ctx, user, pwPolicy, orgIamPolicy, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -152,8 +153,11 @@ func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User,
|
||||
return model.UserToModel(repoUser), nil
|
||||
}
|
||||
|
||||
func (es *UserEventstore) PrepareRegisterUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
|
||||
user.SetEmailAsUsername()
|
||||
func (es *UserEventstore) PrepareRegisterUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy, orgIamPolicy *org_model.OrgIamPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
|
||||
err := user.CheckOrgIamPolicy(orgIamPolicy)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !user.IsValid() || user.Password == nil || user.SecretString == "" {
|
||||
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Errors.User.InvalidData")
|
||||
}
|
||||
@ -175,12 +179,12 @@ func (es *UserEventstore) PrepareRegisterUser(ctx context.Context, user *usr_mod
|
||||
repoUser := model.UserFromModel(user)
|
||||
repoEmailCode := model.EmailCodeFromModel(user.EmailCode)
|
||||
|
||||
aggregates, err := UserRegisterAggregate(ctx, es.AggregateCreator(), repoUser, resourceOwner, repoEmailCode)
|
||||
aggregates, err := UserRegisterAggregate(ctx, es.AggregateCreator(), repoUser, resourceOwner, repoEmailCode, orgIamPolicy.UserLoginMustBeDomain)
|
||||
return repoUser, aggregates, err
|
||||
}
|
||||
|
||||
func (es *UserEventstore) RegisterUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy, resourceOwner string) (*usr_model.User, error) {
|
||||
repoUser, createAggregates, err := es.PrepareRegisterUser(ctx, user, policy, resourceOwner)
|
||||
func (es *UserEventstore) RegisterUser(ctx context.Context, user *usr_model.User, pwPolicy *policy_model.PasswordComplexityPolicy, orgIamPolicy *org_model.OrgIamPolicy, resourceOwner string) (*usr_model.User, error) {
|
||||
repoUser, createAggregates, err := es.PrepareRegisterUser(ctx, user, pwPolicy, orgIamPolicy, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
policy_model "github.com/caos/zitadel/internal/policy/model"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
policy_model "github.com/caos/zitadel/internal/policy/model"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
@ -86,10 +86,11 @@ func TestUserByID(t *testing.T) {
|
||||
func TestCreateUser(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserEventstore
|
||||
ctx context.Context
|
||||
user *model.User
|
||||
policy *policy_model.PasswordComplexityPolicy
|
||||
es *UserEventstore
|
||||
ctx context.Context
|
||||
user *model.User
|
||||
policy *policy_model.PasswordComplexityPolicy
|
||||
orgPolicy *org_model.OrgIamPolicy
|
||||
}
|
||||
type res struct {
|
||||
user *model.User
|
||||
@ -117,7 +118,8 @@ func TestCreateUser(t *testing.T) {
|
||||
IsEmailVerified: true,
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{Sequence: 1},
|
||||
@ -148,7 +150,8 @@ func TestCreateUser(t *testing.T) {
|
||||
IsEmailVerified: true,
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{UserLoginMustBeDomain: false},
|
||||
},
|
||||
res: res{
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{Sequence: 1},
|
||||
@ -184,7 +187,8 @@ func TestCreateUser(t *testing.T) {
|
||||
IsPhoneVerified: true,
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{Sequence: 1},
|
||||
@ -221,7 +225,8 @@ func TestCreateUser(t *testing.T) {
|
||||
IsEmailVerified: true,
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{Sequence: 1},
|
||||
@ -239,6 +244,31 @@ func TestCreateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "create user invalid",
|
||||
args: args{
|
||||
es: GetMockManipulateUser(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create user pw policy nil",
|
||||
args: args{
|
||||
es: GetMockManipulateUser(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create user org policy nil",
|
||||
args: args{
|
||||
es: GetMockManipulateUser(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
@ -249,21 +279,10 @@ func TestCreateUser(t *testing.T) {
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create user policy nil",
|
||||
args: args{
|
||||
es: GetMockManipulateUser(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{AggregateID: "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.CreateUser(tt.args.ctx, tt.args.user, tt.args.policy)
|
||||
result, err := tt.args.es.CreateUser(tt.args.ctx, tt.args.user, tt.args.policy, tt.args.orgPolicy)
|
||||
|
||||
if tt.res.errFunc == nil && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
@ -296,6 +315,7 @@ func TestRegisterUser(t *testing.T) {
|
||||
user *model.User
|
||||
resourceOwner string
|
||||
policy *policy_model.PasswordComplexityPolicy
|
||||
orgPolicy *org_model.OrgIamPolicy
|
||||
}
|
||||
type res struct {
|
||||
user *model.User
|
||||
@ -326,6 +346,7 @@ func TestRegisterUser(t *testing.T) {
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{UserLoginMustBeDomain: true},
|
||||
resourceOwner: "ResourceOwner",
|
||||
},
|
||||
res: res{
|
||||
@ -359,6 +380,7 @@ func TestRegisterUser(t *testing.T) {
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{UserLoginMustBeDomain: false},
|
||||
resourceOwner: "ResourceOwner",
|
||||
},
|
||||
res: res{
|
||||
@ -381,6 +403,7 @@ func TestRegisterUser(t *testing.T) {
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{Sequence: 1}},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
resourceOwner: "ResourceOwner",
|
||||
},
|
||||
res: res{
|
||||
@ -403,6 +426,7 @@ func TestRegisterUser(t *testing.T) {
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
resourceOwner: "ResourceOwner",
|
||||
},
|
||||
res: res{
|
||||
@ -424,14 +448,15 @@ func TestRegisterUser(t *testing.T) {
|
||||
EmailAddress: "EmailAddress",
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no policy",
|
||||
name: "no pw policy",
|
||||
args: args{
|
||||
es: GetMockManipulateUser(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
@ -445,6 +470,28 @@ func TestRegisterUser(t *testing.T) {
|
||||
EmailAddress: "EmailAddress",
|
||||
},
|
||||
},
|
||||
orgPolicy: &org_model.OrgIamPolicy{},
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no org policy",
|
||||
args: args{
|
||||
es: GetMockManipulateUser(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
user: &model.User{ObjectRoot: es_models.ObjectRoot{Sequence: 1},
|
||||
Profile: &model.Profile{
|
||||
UserName: "EmailAddress",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
||||
Email: &model.Email{
|
||||
EmailAddress: "EmailAddress",
|
||||
},
|
||||
},
|
||||
policy: &policy_model.PasswordComplexityPolicy{},
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
@ -453,7 +500,7 @@ func TestRegisterUser(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.RegisterUser(tt.args.ctx, tt.args.user, tt.args.policy, tt.args.resourceOwner)
|
||||
result, err := tt.args.es.RegisterUser(tt.args.ctx, tt.args.user, tt.args.policy, tt.args.orgPolicy, tt.args.resourceOwner)
|
||||
|
||||
if tt.res.errFunc == nil && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
|
@ -5,7 +5,9 @@ import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func UserByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
||||
@ -53,7 +55,7 @@ func UserAggregateOverwriteContext(ctx context.Context, aggCreator *es_models.Ag
|
||||
return aggCreator.NewAggregate(ctx, user.AggregateID, model.UserAggregate, model.UserVersion, user.Sequence, es_models.OverwriteResourceOwner(resourceOwnerID), es_models.OverwriteEditorUser(userID))
|
||||
}
|
||||
|
||||
func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, initCode *model.InitUserCode, phoneCode *model.PhoneCode, resourceOwner string) (_ []*es_models.Aggregate, err error) {
|
||||
func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, initCode *model.InitUserCode, phoneCode *model.PhoneCode, resourceOwner string, userLoginMustBeDomain bool) (_ []*es_models.Aggregate, err error) {
|
||||
if user == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user should not be nil")
|
||||
}
|
||||
@ -67,6 +69,14 @@ func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !userLoginMustBeDomain {
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(org_es_model.OrgAggregate).
|
||||
AggregateIDsFilter()
|
||||
|
||||
validation := addUserNameValidation(user.UserName)
|
||||
agg.SetPrecondition(validationQuery, validation)
|
||||
}
|
||||
|
||||
agg, err = agg.AppendEvent(model.UserAdded, user)
|
||||
if err != nil {
|
||||
@ -107,7 +117,7 @@ func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
}, nil
|
||||
}
|
||||
|
||||
func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, emailCode *model.EmailCode) ([]*es_models.Aggregate, error) {
|
||||
func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, emailCode *model.EmailCode, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
|
||||
if user == nil || resourceOwner == "" || emailCode == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user, resourceowner, emailcode should not be nothing")
|
||||
}
|
||||
@ -117,6 +127,14 @@ func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateC
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !userLoginMustBeDomain {
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(org_es_model.OrgAggregate).
|
||||
AggregateIDsFilter()
|
||||
|
||||
validation := addUserNameValidation(user.UserName)
|
||||
agg.SetPrecondition(validationQuery, validation)
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.UserRegistered, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -152,9 +170,9 @@ func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.Aggregat
|
||||
}, nil
|
||||
}
|
||||
func reservedUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, userName string) (*es_models.Aggregate, error) {
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, userName, model.UserUserNameAggregate, model.UserVersion, 0)
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, userName+resourceOwner, model.UserUserNameAggregate, model.UserVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, userName, model.UserUserNameAggregate, model.UserVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, userName+resourceOwner, model.UserUserNameAggregate, model.UserVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -631,3 +649,44 @@ func isEventValidation(aggregate *es_models.Aggregate, eventType es_models.Event
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func addUserNameValidation(userName string) func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
domains := make([]*org_es_model.OrgDomain, 0)
|
||||
for _, event := range events {
|
||||
switch event.Type {
|
||||
case org_es_model.OrgDomainAdded:
|
||||
domain := new(org_es_model.OrgDomain)
|
||||
domain.SetData(event)
|
||||
case org_es_model.OrgDomainVerified:
|
||||
domain := new(org_es_model.OrgDomain)
|
||||
domain.SetData(event)
|
||||
for _, d := range domains {
|
||||
if d.Domain == domain.Domain {
|
||||
d.Verified = true
|
||||
}
|
||||
}
|
||||
case org_es_model.OrgDomainRemoved:
|
||||
domain := new(org_es_model.OrgDomain)
|
||||
domain.SetData(event)
|
||||
for i, d := range domains {
|
||||
if d.Domain == domain.Domain {
|
||||
domains[i] = domains[len(domains)-1]
|
||||
domains[len(domains)-1] = nil
|
||||
domains = domains[:len(domains)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
split := strings.Split(userName, "@")
|
||||
if len(split) != 2 {
|
||||
return nil
|
||||
}
|
||||
for _, d := range domains {
|
||||
if d.Verified && d.Domain == split[1] {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-us5Zw", "domain already reserved")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ func TestUserCreateAggregate(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
aggregates, err := UserCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.initCode, tt.args.phoneCode, "")
|
||||
aggregates, err := UserCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.initCode, tt.args.phoneCode, "", true)
|
||||
|
||||
if !tt.res.wantErr && len(aggregates) != tt.res.aggregatesLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.aggregatesLen, len(aggregates))
|
||||
@ -348,7 +348,7 @@ func TestUserRegisterAggregate(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
aggregates, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.emailCode)
|
||||
aggregates, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.emailCode, false)
|
||||
|
||||
if tt.res.errFunc == nil && len(aggregates[0].Events) != tt.res.eventLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[0].Events))
|
||||
|
@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
@ -23,39 +24,41 @@ const (
|
||||
UserKeyEmail = "email"
|
||||
UserKeyState = "user_state"
|
||||
UserKeyResourceOwner = "resource_owner"
|
||||
UserKeyLoginNames = "login_names"
|
||||
)
|
||||
|
||||
type UserView struct {
|
||||
ID string `json:"-" gorm:"column:id;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||
State int32 `json:"-" gorm:"column:user_state"`
|
||||
PasswordSet bool `json:"-" gorm:"column:password_set"`
|
||||
PasswordChangeRequired bool `json:"-" gorm:"column:password_change_required"`
|
||||
PasswordChanged time.Time `json:"-" gorm:"column:password_change"`
|
||||
LastLogin time.Time `json:"-" gorm:"column:last_login"`
|
||||
UserName string `json:"userName" gorm:"column:user_name"`
|
||||
FirstName string `json:"firstName" gorm:"column:first_name"`
|
||||
LastName string `json:"lastName" gorm:"column:last_name"`
|
||||
NickName string `json:"nickName" gorm:"column:nick_name"`
|
||||
DisplayName string `json:"displayName" gorm:"column:display_name"`
|
||||
PreferredLanguage string `json:"preferredLanguage" gorm:"column:preferred_language"`
|
||||
Gender int32 `json:"gender" gorm:"column:gender"`
|
||||
Email string `json:"email" gorm:"column:email"`
|
||||
IsEmailVerified bool `json:"-" gorm:"column:is_email_verified"`
|
||||
Phone string `json:"phone" gorm:"column:phone"`
|
||||
IsPhoneVerified bool `json:"-" gorm:"column:is_phone_verified"`
|
||||
Country string `json:"country" gorm:"column:country"`
|
||||
Locality string `json:"locality" gorm:"column:locality"`
|
||||
PostalCode string `json:"postalCode" gorm:"column:postal_code"`
|
||||
Region string `json:"region" gorm:"column:region"`
|
||||
StreetAddress string `json:"streetAddress" gorm:"column:street_address"`
|
||||
OTPState int32 `json:"-" gorm:"column:otp_state"`
|
||||
MfaMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"`
|
||||
MfaInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"`
|
||||
InitRequired bool `json:"-" gorm:"column:init_required"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
ID string `json:"-" gorm:"column:id;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||
State int32 `json:"-" gorm:"column:user_state"`
|
||||
PasswordSet bool `json:"-" gorm:"column:password_set"`
|
||||
PasswordChangeRequired bool `json:"-" gorm:"column:password_change_required"`
|
||||
PasswordChanged time.Time `json:"-" gorm:"column:password_change"`
|
||||
LastLogin time.Time `json:"-" gorm:"column:last_login"`
|
||||
UserName string `json:"userName" gorm:"column:user_name"`
|
||||
LoginNames pq.StringArray `json:"-" gorm:"column:login_names"`
|
||||
FirstName string `json:"firstName" gorm:"column:first_name"`
|
||||
LastName string `json:"lastName" gorm:"column:last_name"`
|
||||
NickName string `json:"nickName" gorm:"column:nick_name"`
|
||||
DisplayName string `json:"displayName" gorm:"column:display_name"`
|
||||
PreferredLanguage string `json:"preferredLanguage" gorm:"column:preferred_language"`
|
||||
Gender int32 `json:"gender" gorm:"column:gender"`
|
||||
Email string `json:"email" gorm:"column:email"`
|
||||
IsEmailVerified bool `json:"-" gorm:"column:is_email_verified"`
|
||||
Phone string `json:"phone" gorm:"column:phone"`
|
||||
IsPhoneVerified bool `json:"-" gorm:"column:is_phone_verified"`
|
||||
Country string `json:"country" gorm:"column:country"`
|
||||
Locality string `json:"locality" gorm:"column:locality"`
|
||||
PostalCode string `json:"postalCode" gorm:"column:postal_code"`
|
||||
Region string `json:"region" gorm:"column:region"`
|
||||
StreetAddress string `json:"streetAddress" gorm:"column:street_address"`
|
||||
OTPState int32 `json:"-" gorm:"column:otp_state"`
|
||||
MfaMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"`
|
||||
MfaInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"`
|
||||
InitRequired bool `json:"-" gorm:"column:init_required"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
}
|
||||
|
||||
func UserFromModel(user *model.UserView) *UserView {
|
||||
@ -70,6 +73,7 @@ func UserFromModel(user *model.UserView) *UserView {
|
||||
PasswordChanged: user.PasswordChanged,
|
||||
LastLogin: user.LastLogin,
|
||||
UserName: user.UserName,
|
||||
LoginNames: user.LoginNames,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
NickName: user.NickName,
|
||||
|
@ -69,6 +69,8 @@ func (key UserSearchKey) ToColumnName() string {
|
||||
return UserKeyState
|
||||
case usr_model.USERSEARCHKEY_RESOURCEOWNER:
|
||||
return UserKeyResourceOwner
|
||||
case usr_model.USERSEARCHKEY_LOGIN_NAMES:
|
||||
return UserKeyLoginNames
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
@ -2,10 +2,12 @@ package view
|
||||
|
||||
import (
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
func UserByID(db *gorm.DB, table, userID string) (*model.UserView, error) {
|
||||
@ -28,6 +30,32 @@ func UserByUserName(db *gorm.DB, table, userName string) (*model.UserView, error
|
||||
return user, err
|
||||
}
|
||||
|
||||
func UserByLoginName(db *gorm.DB, table, loginName string) (*model.UserView, error) {
|
||||
user := new(model.UserView)
|
||||
loginNameQuery := &model.UserSearchQuery{
|
||||
Key: usr_model.USERSEARCHKEY_LOGIN_NAMES,
|
||||
Method: global_model.SEARCHMETHOD_EQUALS_IN_ARRAY,
|
||||
Value: pq.Array([]string{loginName}),
|
||||
}
|
||||
query := view.PrepareGetByQuery(table, loginNameQuery)
|
||||
err := query(db, user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func UsersByOrgID(db *gorm.DB, table, orgID string) ([]*model.UserView, error) {
|
||||
users := make([]*model.UserView, 0)
|
||||
orgIDQuery := &usr_model.UserSearchQuery{
|
||||
Key: usr_model.USERSEARCHKEY_RESOURCEOWNER,
|
||||
Method: global_model.SEARCHMETHOD_EQUALS,
|
||||
Value: orgID,
|
||||
}
|
||||
query := view.PrepareSearchQuery(table, model.UserSearchRequest{
|
||||
Queries: []*usr_model.UserSearchQuery{orgIDQuery},
|
||||
})
|
||||
_, err := query(db, &users)
|
||||
return users, err
|
||||
}
|
||||
|
||||
func SearchUsers(db *gorm.DB, table string, req *usr_model.UserSearchRequest) ([]*model.UserView, int, error) {
|
||||
users := make([]*model.UserView, 0)
|
||||
query := view.PrepareSearchQuery(table, model.UserSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
|
@ -32,7 +32,6 @@ type UserGrantView struct {
|
||||
Email string `json:"-" gorm:"column:email"`
|
||||
ProjectName string `json:"-" gorm:"column:project_name"`
|
||||
OrgName string `json:"-" gorm:"column:org_name"`
|
||||
OrgDomain string `json:"-" gorm:"column:org_domain"`
|
||||
RoleKeys pq.StringArray `json:"roleKeys" gorm:"column:role_keys"`
|
||||
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
@ -57,7 +56,6 @@ func UserGrantFromModel(grant *model.UserGrantView) *UserGrantView {
|
||||
Email: grant.Email,
|
||||
ProjectName: grant.ProjectName,
|
||||
OrgName: grant.OrgName,
|
||||
OrgDomain: grant.OrgDomain,
|
||||
RoleKeys: grant.RoleKeys,
|
||||
Sequence: grant.Sequence,
|
||||
}
|
||||
@ -78,7 +76,6 @@ func UserGrantToModel(grant *UserGrantView) *model.UserGrantView {
|
||||
Email: grant.Email,
|
||||
ProjectName: grant.ProjectName,
|
||||
OrgName: grant.OrgName,
|
||||
OrgDomain: grant.OrgDomain,
|
||||
RoleKeys: grant.RoleKeys,
|
||||
Sequence: grant.Sequence,
|
||||
}
|
||||
|
@ -104,6 +104,8 @@ func SetQuery(query *gorm.DB, key ColumnKey, value interface{}, method model.Sea
|
||||
query = query.Where(column+" < ?", value)
|
||||
case model.SEARCHMETHOD_IN:
|
||||
query = query.Where(column+" IN (?)", value)
|
||||
case model.SEARCHMETHOD_EQUALS_IN_ARRAY:
|
||||
query = query.Where("? <@ "+column, value)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
7
migrations/cockroach/V1.16__login_names.sql
Normal file
7
migrations/cockroach/V1.16__login_names.sql
Normal file
@ -0,0 +1,7 @@
|
||||
BEGIN;
|
||||
|
||||
|
||||
ALTER TABLE auth.users ADD COLUMN login_names TEXT ARRAY;
|
||||
ALTER TABLE management.users ADD COLUMN login_names TEXT ARRAY;
|
||||
|
||||
COMMIT;
|
16
migrations/cockroach/V1.17__org_domains.sql
Normal file
16
migrations/cockroach/V1.17__org_domains.sql
Normal file
@ -0,0 +1,16 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE management.org_domains (
|
||||
creation_date TIMESTAMPTZ,
|
||||
change_date TIMESTAMPTZ,
|
||||
sequence BIGINT,
|
||||
|
||||
domain TEXT,
|
||||
org_id TEXT,
|
||||
verified BOOLEAN,
|
||||
primary_domain BOOLEAN,
|
||||
|
||||
PRIMARY KEY (org_id, domain)
|
||||
);
|
||||
|
||||
COMMIT;
|
@ -34,6 +34,26 @@ var AdminService_AuthMethods = utils_auth.MethodMapping{
|
||||
Permission: "iam.write",
|
||||
CheckParam: "",
|
||||
},
|
||||
|
||||
"/caos.zitadel.admin.api.v1.AdminService/GetOrgIamPolicy": utils_auth.Option{
|
||||
Permission: "iam.policy.read",
|
||||
CheckParam: "",
|
||||
},
|
||||
|
||||
"/caos.zitadel.admin.api.v1.AdminService/CreateOrgIamPolicy": utils_auth.Option{
|
||||
Permission: "iam.policy.write",
|
||||
CheckParam: "",
|
||||
},
|
||||
|
||||
"/caos.zitadel.admin.api.v1.AdminService/UpdateOrgIamPolicy": utils_auth.Option{
|
||||
Permission: "iam.policy.write",
|
||||
CheckParam: "",
|
||||
},
|
||||
|
||||
"/caos.zitadel.admin.api.v1.AdminService/DeleteOrgIamPolicy": utils_auth.Option{
|
||||
Permission: "iam.policy.delete",
|
||||
CheckParam: "",
|
||||
},
|
||||
}
|
||||
|
||||
func AdminService_Authorization_Interceptor(verifier utils_auth.TokenVerifier, authConf *utils_auth.Config) grpc.UnaryServerInterceptor {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -64,10 +64,7 @@ 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 {
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_AdminService_IsOrgUnique_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
@ -137,6 +134,130 @@ func request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Mars
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_GetOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyID
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetOrgIamPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_CreateOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyRequest
|
||||
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)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := client.CreateOrgIamPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_UpdateOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyRequest
|
||||
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)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateOrgIamPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_DeleteOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyID
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := client.DeleteOrgIamPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -315,23 +436,111 @@ func RegisterAdminServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_GetOrgIamPolicy_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.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_AdminService_GetOrgIamPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_GetOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_AdminService_CreateOrgIamPolicy_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.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_AdminService_CreateOrgIamPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_CreateOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_AdminService_UpdateOrgIamPolicy_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.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_AdminService_UpdateOrgIamPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_UpdateOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_AdminService_DeleteOrgIamPolicy_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.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_AdminService_DeleteOrgIamPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_DeleteOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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"}, ""))
|
||||
|
||||
pattern_AdminService_GetOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
|
||||
pattern_AdminService_CreateOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
|
||||
pattern_AdminService_UpdateOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
|
||||
pattern_AdminService_DeleteOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
@ -348,4 +557,12 @@ var (
|
||||
forward_AdminService_SearchOrgs_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_AdminService_SetUpOrg_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_AdminService_GetOrgIamPolicy_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_AdminService_CreateOrgIamPolicy_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_AdminService_UpdateOrgIamPolicy_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_AdminService_DeleteOrgIamPolicy_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
@ -143,6 +143,113 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/orgs/{org_id}/iampolicy": {
|
||||
"get": {
|
||||
"summary": "ORG_IAM_POLICY",
|
||||
"operationId": "GetOrgIamPolicy",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1OrgIamPolicy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "org_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"AdminService"
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"operationId": "DeleteOrgIamPolicy",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"properties": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "org_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"AdminService"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"operationId": "CreateOrgIamPolicy",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1OrgIamPolicy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "org_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1OrgIamPolicyRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"AdminService"
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"operationId": "UpdateOrgIamPolicy",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1OrgIamPolicy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "org_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1OrgIamPolicyRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"AdminService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/ready": {
|
||||
"get": {
|
||||
"summary": "Ready returns status OK as soon as all dependent services are available",
|
||||
@ -167,7 +274,7 @@
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"type": "object"
|
||||
"$ref": "#/definitions/protobufStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -178,6 +285,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 +306,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": {
|
||||
@ -290,6 +455,52 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1OrgIamPolicy": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"org_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_login_must_be_domain": {
|
||||
"type": "boolean",
|
||||
"format": "boolean"
|
||||
},
|
||||
"default": {
|
||||
"type": "boolean",
|
||||
"format": "boolean"
|
||||
},
|
||||
"sequence": {
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
"creation_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"change_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1OrgIamPolicyRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"org_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_login_must_be_domain": {
|
||||
"type": "boolean",
|
||||
"format": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1OrgSearchKey": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -37,6 +37,46 @@ func (m *MockAdminServiceClient) EXPECT() *MockAdminServiceClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateOrgIamPolicy mocks base method
|
||||
func (m *MockAdminServiceClient) CreateOrgIamPolicy(arg0 context.Context, arg1 *grpc.OrgIamPolicyRequest, arg2 ...grpc0.CallOption) (*grpc.OrgIamPolicy, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "CreateOrgIamPolicy", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.OrgIamPolicy)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateOrgIamPolicy indicates an expected call of CreateOrgIamPolicy
|
||||
func (mr *MockAdminServiceClientMockRecorder) CreateOrgIamPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrgIamPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).CreateOrgIamPolicy), varargs...)
|
||||
}
|
||||
|
||||
// DeleteOrgIamPolicy mocks base method
|
||||
func (m *MockAdminServiceClient) DeleteOrgIamPolicy(arg0 context.Context, arg1 *grpc.OrgIamPolicyID, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "DeleteOrgIamPolicy", varargs...)
|
||||
ret0, _ := ret[0].(*emptypb.Empty)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteOrgIamPolicy indicates an expected call of DeleteOrgIamPolicy
|
||||
func (mr *MockAdminServiceClientMockRecorder) DeleteOrgIamPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOrgIamPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).DeleteOrgIamPolicy), varargs...)
|
||||
}
|
||||
|
||||
// GetOrgByID mocks base method
|
||||
func (m *MockAdminServiceClient) GetOrgByID(arg0 context.Context, arg1 *grpc.OrgID, arg2 ...grpc0.CallOption) (*grpc.Org, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -57,6 +97,26 @@ func (mr *MockAdminServiceClientMockRecorder) GetOrgByID(arg0, arg1 interface{},
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrgByID", reflect.TypeOf((*MockAdminServiceClient)(nil).GetOrgByID), varargs...)
|
||||
}
|
||||
|
||||
// GetOrgIamPolicy mocks base method
|
||||
func (m *MockAdminServiceClient) GetOrgIamPolicy(arg0 context.Context, arg1 *grpc.OrgIamPolicyID, arg2 ...grpc0.CallOption) (*grpc.OrgIamPolicy, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetOrgIamPolicy", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.OrgIamPolicy)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetOrgIamPolicy indicates an expected call of GetOrgIamPolicy
|
||||
func (mr *MockAdminServiceClientMockRecorder) GetOrgIamPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrgIamPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).GetOrgIamPolicy), varargs...)
|
||||
}
|
||||
|
||||
// Healthz mocks base method
|
||||
func (m *MockAdminServiceClient) Healthz(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -157,6 +217,26 @@ func (mr *MockAdminServiceClientMockRecorder) SetUpOrg(arg0, arg1 interface{}, a
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUpOrg", reflect.TypeOf((*MockAdminServiceClient)(nil).SetUpOrg), varargs...)
|
||||
}
|
||||
|
||||
// UpdateOrgIamPolicy mocks base method
|
||||
func (m *MockAdminServiceClient) UpdateOrgIamPolicy(arg0 context.Context, arg1 *grpc.OrgIamPolicyRequest, arg2 ...grpc0.CallOption) (*grpc.OrgIamPolicy, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "UpdateOrgIamPolicy", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.OrgIamPolicy)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateOrgIamPolicy indicates an expected call of UpdateOrgIamPolicy
|
||||
func (mr *MockAdminServiceClientMockRecorder) UpdateOrgIamPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOrgIamPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).UpdateOrgIamPolicy), varargs...)
|
||||
}
|
||||
|
||||
// Validate mocks base method
|
||||
func (m *MockAdminServiceClient) Validate(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*structpb.Struct, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -2,10 +2,7 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
func (s *Server) GetOrgByID(ctx context.Context, orgID *OrgID) (_ *Org, err error) {
|
||||
@ -43,56 +40,31 @@ func (s *Server) SetUpOrg(ctx context.Context, orgSetUp *OrgSetUpRequest) (_ *Or
|
||||
return setUpOrgResponseFromModel(setUp), err
|
||||
}
|
||||
|
||||
func orgSearchRequestToModel(req *OrgSearchRequest) *org_model.OrgSearchRequest {
|
||||
return &org_model.OrgSearchRequest{
|
||||
Limit: req.Limit,
|
||||
Asc: req.Asc,
|
||||
Offset: req.Offset,
|
||||
Queries: orgQueriesToModel(req.Queries),
|
||||
SortingColumn: orgQueryKeyToModel(req.SortingColumn),
|
||||
func (s *Server) GetOrgIamPolicy(ctx context.Context, in *OrgIamPolicyID) (_ *OrgIamPolicy, err error) {
|
||||
policy, err := s.org.GetOrgIamPolicyByID(ctx, in.OrgId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return orgIamPolicyFromModel(policy), err
|
||||
}
|
||||
|
||||
func orgQueriesToModel(queries []*OrgSearchQuery) []*org_model.OrgSearchQuery {
|
||||
modelQueries := make([]*org_model.OrgSearchQuery, len(queries))
|
||||
|
||||
for i, query := range queries {
|
||||
modelQueries[i] = orgQueryToModel(query)
|
||||
func (s *Server) CreateOrgIamPolicy(ctx context.Context, in *OrgIamPolicyRequest) (_ *OrgIamPolicy, err error) {
|
||||
policy, err := s.org.CreateOrgIamPolicy(ctx, orgIamPolicyRequestToModel(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return modelQueries
|
||||
return orgIamPolicyFromModel(policy), err
|
||||
}
|
||||
|
||||
func orgQueryToModel(query *OrgSearchQuery) *org_model.OrgSearchQuery {
|
||||
return &org_model.OrgSearchQuery{
|
||||
Key: orgQueryKeyToModel(query.Key),
|
||||
Value: query.Value,
|
||||
Method: orgQueryMethodToModel(query.Method),
|
||||
func (s *Server) UpdateOrgIamPolicy(ctx context.Context, in *OrgIamPolicyRequest) (_ *OrgIamPolicy, err error) {
|
||||
policy, err := s.org.ChangeOrgIamPolicy(ctx, orgIamPolicyRequestToModel(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return orgIamPolicyFromModel(policy), err
|
||||
}
|
||||
|
||||
func orgQueryKeyToModel(key OrgSearchKey) org_model.OrgSearchKey {
|
||||
switch key {
|
||||
case OrgSearchKey_ORGSEARCHKEY_DOMAIN:
|
||||
return org_model.ORGSEARCHKEY_ORG_DOMAIN
|
||||
case OrgSearchKey_ORGSEARCHKEY_ORG_NAME:
|
||||
return org_model.ORGSEARCHKEY_ORG_NAME
|
||||
case OrgSearchKey_ORGSEARCHKEY_STATE:
|
||||
return org_model.ORGSEARCHKEY_STATE
|
||||
default:
|
||||
return org_model.ORGSEARCHKEY_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func orgQueryMethodToModel(method OrgSearchMethod) model.SearchMethod {
|
||||
switch method {
|
||||
case OrgSearchMethod_ORGSEARCHMETHOD_CONTAINS:
|
||||
return model.SEARCHMETHOD_CONTAINS
|
||||
case OrgSearchMethod_ORGSEARCHMETHOD_EQUALS:
|
||||
return model.SEARCHMETHOD_EQUALS
|
||||
case OrgSearchMethod_ORGSEARCHMETHOD_STARTS_WITH:
|
||||
return model.SEARCHMETHOD_STARTS_WITH
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
func (s *Server) DeleteOrgIamPolicy(ctx context.Context, in *OrgIamPolicyID) (_ *empty.Empty, err error) {
|
||||
err = s.org.RemoveOrgIamPolicy(ctx, in.OrgId)
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package grpc
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
admin_model "github.com/caos/zitadel/internal/admin/model"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
@ -18,8 +20,8 @@ func setUpRequestToModel(setUp *OrgSetUpRequest) *admin_model.SetupOrg {
|
||||
|
||||
func orgCreateRequestToModel(org *CreateOrgRequest) *org_model.Org {
|
||||
return &org_model.Org{
|
||||
Domain: org.Domain,
|
||||
Name: org.Name,
|
||||
Domains: []*org_model.OrgDomain{&org_model.OrgDomain{Domain: org.Domain}},
|
||||
Name: org.Name,
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +84,6 @@ func orgFromModel(org *org_model.Org) *Org {
|
||||
logging.Log("GRPC-dVnoj").OnError(err).Debug("unable to get timestamp from time")
|
||||
|
||||
return &Org{
|
||||
Domain: org.Domain,
|
||||
ChangeDate: changeDate,
|
||||
CreationDate: creationDate,
|
||||
Id: org.AggregateID,
|
||||
@ -99,7 +100,6 @@ func orgViewFromModel(org *org_model.OrgView) *Org {
|
||||
logging.Log("GRPC-dVnoj").OnError(err).Debug("unable to get timestamp from time")
|
||||
|
||||
return &Org{
|
||||
Domain: org.Domain,
|
||||
ChangeDate: changeDate,
|
||||
CreationDate: creationDate,
|
||||
Id: org.ID,
|
||||
@ -196,3 +196,84 @@ func userStateFromModel(state usr_model.UserState) UserState {
|
||||
return UserState_USERSTATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func orgSearchRequestToModel(req *OrgSearchRequest) *org_model.OrgSearchRequest {
|
||||
return &org_model.OrgSearchRequest{
|
||||
Limit: req.Limit,
|
||||
Asc: req.Asc,
|
||||
Offset: req.Offset,
|
||||
Queries: orgQueriesToModel(req.Queries),
|
||||
SortingColumn: orgQueryKeyToModel(req.SortingColumn),
|
||||
}
|
||||
}
|
||||
|
||||
func orgQueriesToModel(queries []*OrgSearchQuery) []*org_model.OrgSearchQuery {
|
||||
modelQueries := make([]*org_model.OrgSearchQuery, len(queries))
|
||||
|
||||
for i, query := range queries {
|
||||
modelQueries[i] = orgQueryToModel(query)
|
||||
}
|
||||
|
||||
return modelQueries
|
||||
}
|
||||
|
||||
func orgQueryToModel(query *OrgSearchQuery) *org_model.OrgSearchQuery {
|
||||
return &org_model.OrgSearchQuery{
|
||||
Key: orgQueryKeyToModel(query.Key),
|
||||
Value: query.Value,
|
||||
Method: orgQueryMethodToModel(query.Method),
|
||||
}
|
||||
}
|
||||
|
||||
func orgQueryKeyToModel(key OrgSearchKey) org_model.OrgSearchKey {
|
||||
switch key {
|
||||
case OrgSearchKey_ORGSEARCHKEY_DOMAIN:
|
||||
return org_model.ORGSEARCHKEY_ORG_DOMAIN
|
||||
case OrgSearchKey_ORGSEARCHKEY_ORG_NAME:
|
||||
return org_model.ORGSEARCHKEY_ORG_NAME
|
||||
case OrgSearchKey_ORGSEARCHKEY_STATE:
|
||||
return org_model.ORGSEARCHKEY_STATE
|
||||
default:
|
||||
return org_model.ORGSEARCHKEY_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func orgQueryMethodToModel(method OrgSearchMethod) model.SearchMethod {
|
||||
switch method {
|
||||
case OrgSearchMethod_ORGSEARCHMETHOD_CONTAINS:
|
||||
return model.SEARCHMETHOD_CONTAINS
|
||||
case OrgSearchMethod_ORGSEARCHMETHOD_EQUALS:
|
||||
return model.SEARCHMETHOD_EQUALS
|
||||
case OrgSearchMethod_ORGSEARCHMETHOD_STARTS_WITH:
|
||||
return model.SEARCHMETHOD_STARTS_WITH
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func orgIamPolicyFromModel(policy *org_model.OrgIamPolicy) *OrgIamPolicy {
|
||||
creationDate, err := ptypes.TimestampProto(policy.CreationDate)
|
||||
logging.Log("GRPC-ush36").OnError(err).Debug("unable to get timestamp from time")
|
||||
|
||||
changeDate, err := ptypes.TimestampProto(policy.ChangeDate)
|
||||
logging.Log("GRPC-Ps9fW").OnError(err).Debug("unable to get timestamp from time")
|
||||
|
||||
return &OrgIamPolicy{
|
||||
OrgId: policy.AggregateID,
|
||||
Description: policy.Description,
|
||||
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
|
||||
Default: policy.Default,
|
||||
CreationDate: creationDate,
|
||||
ChangeDate: changeDate,
|
||||
}
|
||||
}
|
||||
|
||||
func orgIamPolicyRequestToModel(policy *OrgIamPolicyRequest) *org_model.OrgIamPolicy {
|
||||
return &org_model.OrgIamPolicy{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: policy.OrgId,
|
||||
},
|
||||
Description: policy.Description,
|
||||
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,49 @@ service AdminService {
|
||||
permission: "iam.write"
|
||||
};
|
||||
}
|
||||
|
||||
//ORG_IAM_POLICY
|
||||
rpc GetOrgIamPolicy(OrgIamPolicyID) returns (OrgIamPolicy) {
|
||||
option (google.api.http) = {
|
||||
get: "/orgs/{org_id}/iampolicy"
|
||||
};
|
||||
|
||||
option (caos.zitadel.utils.v1.auth_option) = {
|
||||
permission: "iam.policy.read"
|
||||
};
|
||||
}
|
||||
|
||||
rpc CreateOrgIamPolicy(OrgIamPolicyRequest) returns (OrgIamPolicy) {
|
||||
option (google.api.http) = {
|
||||
post: "/orgs/{org_id}/iampolicy"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (caos.zitadel.utils.v1.auth_option) = {
|
||||
permission: "iam.policy.write"
|
||||
};
|
||||
}
|
||||
|
||||
rpc UpdateOrgIamPolicy(OrgIamPolicyRequest) returns (OrgIamPolicy) {
|
||||
option (google.api.http) = {
|
||||
put: "/orgs/{org_id}/iampolicy"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (caos.zitadel.utils.v1.auth_option) = {
|
||||
permission: "iam.policy.write"
|
||||
};
|
||||
}
|
||||
|
||||
rpc DeleteOrgIamPolicy(OrgIamPolicyID) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {
|
||||
delete: "/orgs/{org_id}/iampolicy"
|
||||
};
|
||||
|
||||
option (caos.zitadel.utils.v1.auth_option) = {
|
||||
permission: "iam.policy.delete"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
message OrgID {
|
||||
@ -235,5 +278,25 @@ enum Gender {
|
||||
|
||||
message CreateOrgRequest {
|
||||
string name = 1 [(validate.rules).string.min_len = 1];
|
||||
string domain = 2 [(validate.rules).string.min_len = 1];
|
||||
string domain = 2;
|
||||
}
|
||||
|
||||
message OrgIamPolicy {
|
||||
string org_id = 1;
|
||||
string description = 2;
|
||||
bool user_login_must_be_domain = 3;
|
||||
bool default = 4;
|
||||
uint64 sequence = 5;
|
||||
google.protobuf.Timestamp creation_date = 6;
|
||||
google.protobuf.Timestamp change_date = 7;
|
||||
}
|
||||
|
||||
message OrgIamPolicyRequest {
|
||||
string org_id = 1;
|
||||
string description = 2;
|
||||
bool user_login_must_be_domain = 3;
|
||||
}
|
||||
|
||||
message OrgIamPolicyID {
|
||||
string org_id = 1;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -871,53 +871,53 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_AuthService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, ""))
|
||||
|
||||
pattern_AuthService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, ""))
|
||||
|
||||
pattern_AuthService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"me", "usersessions"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"me", "usersessions"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, ""))
|
||||
|
||||
pattern_AuthService_UpdateMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_UpdateMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, ""))
|
||||
|
||||
pattern_AuthService_ChangeMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_ChangeMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, ""))
|
||||
|
||||
pattern_AuthService_VerifyMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_verify"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_VerifyMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_verify"}, ""))
|
||||
|
||||
pattern_AuthService_ResendMyEmailVerificationMail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_resendverification"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_ResendMyEmailVerificationMail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_resendverification"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, ""))
|
||||
|
||||
pattern_AuthService_ChangeMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_ChangeMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, ""))
|
||||
|
||||
pattern_AuthService_VerifyMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_verify"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_VerifyMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_verify"}, ""))
|
||||
|
||||
pattern_AuthService_ResendMyPhoneVerificationCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_resendverification"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_ResendMyPhoneVerificationCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_resendverification"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, ""))
|
||||
|
||||
pattern_AuthService_UpdateMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_UpdateMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyMfas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "mfas"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyMfas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "mfas"}, ""))
|
||||
|
||||
pattern_AuthService_ChangeMyPassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "passwords", "_change"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_ChangeMyPassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "passwords", "_change"}, ""))
|
||||
|
||||
pattern_AuthService_AddMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_AddMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, ""))
|
||||
|
||||
pattern_AuthService_VerifyMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"users", "me", "mfa", "otp", "_verify"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_VerifyMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"users", "me", "mfa", "otp", "_verify"}, ""))
|
||||
|
||||
pattern_AuthService_RemoveMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_RemoveMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, ""))
|
||||
|
||||
pattern_AuthService_SearchMyUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"usergrants", "me", "_search"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_SearchMyUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"usergrants", "me", "_search"}, ""))
|
||||
|
||||
pattern_AuthService_SearchMyProjectOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"global", "projectorgs", "_search"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_SearchMyProjectOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"global", "projectorgs", "_search"}, ""))
|
||||
|
||||
pattern_AuthService_GetMyZitadelPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"permissions", "zitadel", "me"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
pattern_AuthService_GetMyZitadelPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"permissions", "zitadel", "me"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user