mirror of
https://github.com/zitadel/zitadel.git
synced 2025-07-29 08:33:57 +00:00
feat(cli): setup (#3267)
* commander * commander * selber! * move to packages * fix(errors): implement Is interface * test: command * test: commands * add init steps * setup tenant * add default step yaml * possibility to set password * merge v2 into v2-commander * fix: rename iam command side to instance * fix: rename iam command side to instance * fix: rename iam command side to instance * fix: rename iam command side to instance * fix: search query builder can filter events in memory * fix: filters for add member * fix(setup): add `ExternalSecure` to config * chore: name iam to instance * fix: matching * remove unsued func * base url * base url * test(command): filter funcs * test: commands * fix: rename orgiampolicy to domain policy * start from init * commands * config * fix indexes and add constraints * fixes * fix: merge conflicts * fix: protos * fix: md files * setup * add deprecated org iam policy again * typo * fix search query * fix filter * Apply suggestions from code review * remove custom org from org setup * add todos for verification * change apps creation * simplify package structure * fix error * move preparation helper for tests * fix unique constraints * fix config mapping in setup * fix error handling in encryption_keys.go * fix projection config * fix query from old views to projection * fix setup of mgmt api * set iam project and fix instance projection * imports Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
This commit is contained in:
parent
9d4f296c62
commit
c5b99274d7
@ -26,6 +26,7 @@ func New() *cobra.Command {
|
|||||||
initialise.New(),
|
initialise.New(),
|
||||||
setup.New(),
|
setup.New(),
|
||||||
start.New(),
|
start.New(),
|
||||||
|
start.NewStartFromInit(),
|
||||||
key.New(),
|
key.New(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,13 +1,29 @@
|
|||||||
package initialise
|
package initialise
|
||||||
|
|
||||||
import "github.com/caos/zitadel/internal/database"
|
import (
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/database"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Database database.Config
|
Database database.Config
|
||||||
AdminUser database.User
|
AdminUser database.User
|
||||||
|
Log *logging.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func adminConfig(config Config) database.Config {
|
func MustNewConfig(v *viper.Viper) *Config {
|
||||||
|
config := new(Config)
|
||||||
|
err := v.Unmarshal(config)
|
||||||
|
logging.OnError(err).Fatal("unable to read config")
|
||||||
|
|
||||||
|
err = config.Log.SetLogger()
|
||||||
|
logging.OnError(err).Fatal("unable to set logger")
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminConfig(config *Config) database.Config {
|
||||||
adminConfig := config.Database
|
adminConfig := config.Database
|
||||||
adminConfig.Username = config.AdminUser.Username
|
adminConfig.Username = config.AdminUser.Username
|
||||||
adminConfig.Password = config.AdminUser.Password
|
adminConfig.Password = config.AdminUser.Password
|
||||||
|
@ -8,9 +8,6 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
//sql import
|
|
||||||
_ "github.com/lib/pq"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/database"
|
"github.com/caos/zitadel/internal/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,20 +25,10 @@ The user provided by flags needs priviledge to
|
|||||||
- see other users and create a new one if the user does not exist
|
- see other users and create a new one if the user does not exist
|
||||||
- grant all rights of the ZITADEL database to the user created if not yet set
|
- grant all rights of the ZITADEL database to the user created if not yet set
|
||||||
`,
|
`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
config := Config{}
|
config := MustNewConfig(viper.GetViper())
|
||||||
if err := viper.Unmarshal(&config); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := initialise(config,
|
|
||||||
VerifyUser(config.Database.User.Username, config.Database.User.Password),
|
|
||||||
VerifyDatabase(config.Database.Database),
|
|
||||||
VerifyGrant(config.Database.Database, config.Database.User.Username),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return verifyZitadel(config.Database)
|
InitAll(config)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +36,19 @@ The user provided by flags needs priviledge to
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialise(config Config, steps ...func(*sql.DB) error) error {
|
func InitAll(config *Config) {
|
||||||
|
err := initialise(config,
|
||||||
|
VerifyUser(config.Database.Username, config.Database.Password),
|
||||||
|
VerifyDatabase(config.Database.Database),
|
||||||
|
VerifyGrant(config.Database.Database, config.Database.Username),
|
||||||
|
)
|
||||||
|
logging.OnError(err).Fatal("unable to initialize the database")
|
||||||
|
|
||||||
|
err = verifyZitadel(config.Database)
|
||||||
|
logging.OnError(err).Fatal("unable to initialize ZITADEL")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initialise(config *Config, steps ...func(*sql.DB) error) error {
|
||||||
logging.Info("initialization started")
|
logging.Info("initialization started")
|
||||||
|
|
||||||
db, err := database.Connect(adminConfig(config))
|
db, err := database.Connect(adminConfig(config))
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
CREATE TABLE eventstore.unique_constraints (
|
CREATE TABLE eventstore.unique_constraints (
|
||||||
|
instance_id TEXT,
|
||||||
unique_type TEXT,
|
unique_type TEXT,
|
||||||
unique_field TEXT,
|
unique_field TEXT,
|
||||||
PRIMARY KEY (unique_type, unique_field)
|
PRIMARY KEY (instance_id, unique_type, unique_field)
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
@ -30,12 +31,11 @@ The user provided by flags needs priviledge to
|
|||||||
- see other users and create a new one if the user does not exist
|
- see other users and create a new one if the user does not exist
|
||||||
- grant all rights of the ZITADEL database to the user created if not yet set
|
- grant all rights of the ZITADEL database to the user created if not yet set
|
||||||
`,
|
`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
config := Config{}
|
config := MustNewConfig(viper.New())
|
||||||
if err := viper.Unmarshal(&config); err != nil {
|
|
||||||
return err
|
err := initialise(config, VerifyDatabase(config.Database.Database))
|
||||||
}
|
logging.OnError(err).Fatal("unable to initialize the database")
|
||||||
return initialise(config, VerifyDatabase(config.Database.Database))
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,11 @@ func newGrant() *cobra.Command {
|
|||||||
Prereqesits:
|
Prereqesits:
|
||||||
- cockroachdb
|
- cockroachdb
|
||||||
`,
|
`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
config := Config{}
|
config := MustNewConfig(viper.New())
|
||||||
if err := viper.Unmarshal(&config); err != nil {
|
|
||||||
return err
|
err := initialise(config, VerifyGrant(config.Database.Database, config.Database.User.Username))
|
||||||
}
|
logging.OnError(err).Fatal("unable to set grant")
|
||||||
return initialise(config, VerifyGrant(config.Database.Database, config.Database.User.Username))
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,11 @@ The user provided by flags needs priviledge to
|
|||||||
- see other users and create a new one if the user does not exist
|
- see other users and create a new one if the user does not exist
|
||||||
- grant all rights of the ZITADEL database to the user created if not yet set
|
- grant all rights of the ZITADEL database to the user created if not yet set
|
||||||
`,
|
`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
config := Config{}
|
config := MustNewConfig(viper.New())
|
||||||
if err := viper.Unmarshal(&config); err != nil {
|
|
||||||
return err
|
err := initialise(config, VerifyUser(config.Database.Username, config.Database.Password))
|
||||||
}
|
logging.OnError(err).Fatal("unable to init user")
|
||||||
return initialise(config, VerifyUser(config.Database.User.Username, config.Database.User.Password))
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ func VerifyZitadel(db *sql.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func verifyZitadel(config database.Config) error {
|
func verifyZitadel(config database.Config) error {
|
||||||
logging.WithFields("database", config.Database).Info("verify database")
|
logging.WithFields("database", config.Database).Info("verify zitadel")
|
||||||
db, err := database.Connect(config)
|
db, err := database.Connect(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -3,27 +3,27 @@ CREATE SCHEMA adminapi;
|
|||||||
CREATE TABLE adminapi.locks (
|
CREATE TABLE adminapi.locks (
|
||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adminapi.current_sequences (
|
CREATE TABLE adminapi.current_sequences (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
aggregate_type TEXT,
|
|
||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, aggregate_type)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adminapi.failed_events (
|
CREATE TABLE adminapi.failed_events (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
error TEXT,
|
err_msg TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adminapi.styling (
|
CREATE TABLE adminapi.styling (
|
||||||
|
@ -3,27 +3,27 @@ CREATE SCHEMA auth;
|
|||||||
CREATE TABLE auth.locks (
|
CREATE TABLE auth.locks (
|
||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.current_sequences (
|
CREATE TABLE auth.current_sequences (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
aggregate_type TEXT,
|
|
||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, aggregate_type)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.failed_events (
|
CREATE TABLE auth.failed_events (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
error TEXT,
|
err_msg TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.users (
|
CREATE TABLE auth.users (
|
||||||
|
@ -3,27 +3,27 @@ CREATE SCHEMA authz;
|
|||||||
CREATE TABLE authz.locks (
|
CREATE TABLE authz.locks (
|
||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE authz.current_sequences (
|
CREATE TABLE authz.current_sequences (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
aggregate_type TEXT,
|
|
||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, aggregate_type)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE authz.failed_events (
|
CREATE TABLE authz.failed_events (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
error TEXT,
|
err_msg TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE authz.user_memberships (
|
CREATE TABLE authz.user_memberships (
|
||||||
|
@ -3,27 +3,27 @@ CREATE SCHEMA notification;
|
|||||||
CREATE TABLE notification.locks (
|
CREATE TABLE notification.locks (
|
||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE notification.current_sequences (
|
CREATE TABLE notification.current_sequences (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
aggregate_type TEXT,
|
|
||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, aggregate_type)
|
PRIMARY KEY (view_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE notification.failed_events (
|
CREATE TABLE notification.failed_events (
|
||||||
projection_name TEXT,
|
view_name TEXT,
|
||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
error TEXT,
|
err_msg TEXT,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE notification.notify_users (
|
CREATE TABLE notification.notify_users (
|
||||||
|
22
cmd/admin/setup/02.go
Normal file
22
cmd/admin/setup/02.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package setup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
command "github.com/caos/zitadel/internal/command/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DefaultInstance struct {
|
||||||
|
cmd *command.Command
|
||||||
|
InstanceSetup command.InstanceSetup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
||||||
|
_, err := mig.cmd.SetUpInstance(ctx, &mig.InstanceSetup)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *DefaultInstance) String() string {
|
||||||
|
return "02_default_instance"
|
||||||
|
}
|
@ -1,13 +1,58 @@
|
|||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
"github.com/caos/zitadel/internal/config/hook"
|
||||||
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
"github.com/caos/zitadel/internal/database"
|
"github.com/caos/zitadel/internal/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Database database.Config
|
Database database.Config
|
||||||
|
SystemDefaults systemdefaults.SystemDefaults
|
||||||
|
InternalAuthZ authz.Config
|
||||||
|
ExternalPort uint16
|
||||||
|
ExternalDomain string
|
||||||
|
ExternalSecure bool
|
||||||
|
Log *logging.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustNewConfig(v *viper.Viper) *Config {
|
||||||
|
config := new(Config)
|
||||||
|
err := v.Unmarshal(config)
|
||||||
|
logging.OnError(err).Fatal("unable to read config")
|
||||||
|
|
||||||
|
err = config.Log.SetLogger()
|
||||||
|
logging.OnError(err).Fatal("unable to set logger")
|
||||||
|
|
||||||
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
type Steps struct {
|
type Steps struct {
|
||||||
S1ProjectionTable *ProjectionTable
|
S1ProjectionTable *ProjectionTable
|
||||||
|
S2DefaultInstance *DefaultInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustNewSteps(v *viper.Viper) *Steps {
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(bytes.NewBuffer(defaultSteps))
|
||||||
|
logging.OnError(err).Fatal("unable to read setup steps")
|
||||||
|
|
||||||
|
steps := new(Steps)
|
||||||
|
err = v.Unmarshal(steps,
|
||||||
|
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
|
||||||
|
hook.Base64ToBytesHookFunc(),
|
||||||
|
hook.TagToLanguageHookFunc(),
|
||||||
|
mapstructure.StringToTimeDurationHookFunc(),
|
||||||
|
mapstructure.StringToSliceHookFunc(","),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
logging.OnError(err).Fatal("unable to read steps")
|
||||||
|
return steps
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
@ -9,6 +8,8 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
http_util "github.com/caos/zitadel/internal/api/http"
|
||||||
|
command "github.com/caos/zitadel/internal/command/v2"
|
||||||
"github.com/caos/zitadel/internal/database"
|
"github.com/caos/zitadel/internal/database"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/migration"
|
"github.com/caos/zitadel/internal/migration"
|
||||||
@ -27,32 +28,30 @@ func New() *cobra.Command {
|
|||||||
Requirements:
|
Requirements:
|
||||||
- cockroachdb`,
|
- cockroachdb`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
config := new(Config)
|
config := MustNewConfig(viper.GetViper())
|
||||||
err := viper.Unmarshal(config)
|
steps := MustNewSteps(viper.New())
|
||||||
logging.OnError(err).Fatal("unable to read config")
|
|
||||||
|
|
||||||
v := viper.New()
|
Setup(config, steps)
|
||||||
v.SetConfigType("yaml")
|
|
||||||
err = v.ReadConfig(bytes.NewBuffer(defaultSteps))
|
|
||||||
logging.OnError(err).Fatal("unable to read setup steps")
|
|
||||||
|
|
||||||
steps := new(Steps)
|
|
||||||
err = v.Unmarshal(steps)
|
|
||||||
logging.OnError(err).Fatal("unable to read steps")
|
|
||||||
|
|
||||||
setup(config, steps)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(config *Config, steps *Steps) {
|
func Setup(config *Config, steps *Steps) {
|
||||||
dbClient, err := database.Connect(config.Database)
|
dbClient, err := database.Connect(config.Database)
|
||||||
logging.OnError(err).Fatal("unable to connect to database")
|
logging.OnError(err).Fatal("unable to connect to database")
|
||||||
|
|
||||||
eventstoreClient, err := eventstore.Start(dbClient)
|
eventstoreClient, err := eventstore.Start(dbClient)
|
||||||
logging.OnError(err).Fatal("unable to start eventstore")
|
logging.OnError(err).Fatal("unable to start eventstore")
|
||||||
|
migration.RegisterMappers(eventstoreClient)
|
||||||
|
|
||||||
|
cmd := command.New(eventstoreClient, "localhost", config.SystemDefaults)
|
||||||
|
|
||||||
|
steps.S2DefaultInstance.cmd = cmd
|
||||||
steps.S1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
steps.S1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
||||||
|
steps.S2DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
||||||
|
steps.S2DefaultInstance.InstanceSetup.Zitadel.BaseURL = http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
||||||
|
|
||||||
migration.Migrate(context.Background(), eventstoreClient, steps.S1ProjectionTable)
|
ctx := context.Background()
|
||||||
|
migration.Migrate(ctx, eventstoreClient, steps.S1ProjectionTable)
|
||||||
|
migration.Migrate(ctx, eventstoreClient, steps.S2DefaultInstance)
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
66
cmd/admin/start/config.go
Normal file
66
cmd/admin/start/config.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package start
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/logging"
|
||||||
|
admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing"
|
||||||
|
internal_authz "github.com/caos/zitadel/internal/api/authz"
|
||||||
|
"github.com/caos/zitadel/internal/api/http/middleware"
|
||||||
|
"github.com/caos/zitadel/internal/api/oidc"
|
||||||
|
"github.com/caos/zitadel/internal/api/ui/console"
|
||||||
|
"github.com/caos/zitadel/internal/api/ui/login"
|
||||||
|
auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
|
||||||
|
"github.com/caos/zitadel/internal/authz"
|
||||||
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
|
"github.com/caos/zitadel/internal/database"
|
||||||
|
"github.com/caos/zitadel/internal/notification"
|
||||||
|
"github.com/caos/zitadel/internal/query/projection"
|
||||||
|
static_config "github.com/caos/zitadel/internal/static/config"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Log *logging.Config
|
||||||
|
Port uint16
|
||||||
|
ExternalPort uint16
|
||||||
|
ExternalDomain string
|
||||||
|
ExternalSecure bool
|
||||||
|
Database database.Config
|
||||||
|
Projections projection.Config
|
||||||
|
AuthZ authz.Config
|
||||||
|
Auth auth_es.Config
|
||||||
|
Admin admin_es.Config
|
||||||
|
UserAgentCookie *middleware.UserAgentCookieConfig
|
||||||
|
OIDC oidc.Config
|
||||||
|
Login login.Config
|
||||||
|
Console console.Config
|
||||||
|
Notification notification.Config
|
||||||
|
AssetStorage static_config.AssetStorageConfig
|
||||||
|
InternalAuthZ internal_authz.Config
|
||||||
|
SystemDefaults systemdefaults.SystemDefaults
|
||||||
|
EncryptionKeys *encryptionKeyConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustNewConfig(v *viper.Viper) *Config {
|
||||||
|
config := new(Config)
|
||||||
|
|
||||||
|
err := v.Unmarshal(config)
|
||||||
|
logging.OnError(err).Fatal("unable to read config")
|
||||||
|
|
||||||
|
err = config.Log.SetLogger()
|
||||||
|
logging.OnError(err).Fatal("unable to set logger")
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
type encryptionKeyConfig struct {
|
||||||
|
DomainVerification *crypto.KeyConfig
|
||||||
|
IDPConfig *crypto.KeyConfig
|
||||||
|
OIDC *crypto.KeyConfig
|
||||||
|
OTP *crypto.KeyConfig
|
||||||
|
SMS *crypto.KeyConfig
|
||||||
|
SMTP *crypto.KeyConfig
|
||||||
|
User *crypto.KeyConfig
|
||||||
|
CSRFCookieKeyID string
|
||||||
|
UserAgentCookieKeyID string
|
||||||
|
}
|
@ -35,7 +35,7 @@ type encryptionKeys struct {
|
|||||||
func ensureEncryptionKeys(keyConfig *encryptionKeyConfig, keyStorage crypto.KeyStorage) (*encryptionKeys, error) {
|
func ensureEncryptionKeys(keyConfig *encryptionKeyConfig, keyStorage crypto.KeyStorage) (*encryptionKeys, error) {
|
||||||
keys, err := keyStorage.ReadKeys()
|
keys, err := keyStorage.ReadKeys()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
if err := createDefaultKeys(keyStorage); err != nil {
|
if err := createDefaultKeys(keyStorage); err != nil {
|
||||||
|
31
cmd/admin/start/flags.go
Normal file
31
cmd/admin/start/flags.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package start
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startFlags(cmd *cobra.Command) {
|
||||||
|
bindUint16Flag(cmd, "port", "port to run ZITADEL on")
|
||||||
|
bindStringFlag(cmd, "externalDomain", "domain ZITADEL will be exposed on")
|
||||||
|
bindStringFlag(cmd, "externalPort", "port ZITADEL will be exposed on")
|
||||||
|
bindBoolFlag(cmd, "externalSecure", "if ZITADEL will be served on HTTPS")
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String(flagMasterKey, "", "masterkey for en/decryption keys")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindStringFlag(cmd *cobra.Command, name, description string) {
|
||||||
|
cmd.PersistentFlags().String(name, viper.GetString(name), description)
|
||||||
|
viper.BindPFlag(name, cmd.PersistentFlags().Lookup(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindUint16Flag(cmd *cobra.Command, name, description string) {
|
||||||
|
cmd.PersistentFlags().Uint16(name, uint16(viper.GetUint(name)), description)
|
||||||
|
viper.BindPFlag(name, cmd.PersistentFlags().Lookup(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindBoolFlag(cmd *cobra.Command, name, description string) {
|
||||||
|
cmd.PersistentFlags().Bool(name, viper.GetBool(name), description)
|
||||||
|
viper.BindPFlag(name, cmd.PersistentFlags().Lookup(name))
|
||||||
|
}
|
@ -15,7 +15,6 @@ import (
|
|||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
@ -37,17 +36,13 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/authz"
|
"github.com/caos/zitadel/internal/authz"
|
||||||
authz_repo "github.com/caos/zitadel/internal/authz/repository"
|
authz_repo "github.com/caos/zitadel/internal/authz/repository"
|
||||||
"github.com/caos/zitadel/internal/command"
|
"github.com/caos/zitadel/internal/command"
|
||||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
|
||||||
"github.com/caos/zitadel/internal/crypto"
|
|
||||||
cryptoDB "github.com/caos/zitadel/internal/crypto/database"
|
cryptoDB "github.com/caos/zitadel/internal/crypto/database"
|
||||||
"github.com/caos/zitadel/internal/database"
|
"github.com/caos/zitadel/internal/database"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/id"
|
"github.com/caos/zitadel/internal/id"
|
||||||
"github.com/caos/zitadel/internal/notification"
|
"github.com/caos/zitadel/internal/notification"
|
||||||
"github.com/caos/zitadel/internal/query"
|
"github.com/caos/zitadel/internal/query"
|
||||||
"github.com/caos/zitadel/internal/query/projection"
|
|
||||||
"github.com/caos/zitadel/internal/static"
|
"github.com/caos/zitadel/internal/static"
|
||||||
static_config "github.com/caos/zitadel/internal/static/config"
|
|
||||||
"github.com/caos/zitadel/internal/webauthn"
|
"github.com/caos/zitadel/internal/webauthn"
|
||||||
"github.com/caos/zitadel/openapi"
|
"github.com/caos/zitadel/openapi"
|
||||||
)
|
)
|
||||||
@ -64,82 +59,19 @@ func New() *cobra.Command {
|
|||||||
Requirements:
|
Requirements:
|
||||||
- cockroachdb`,
|
- cockroachdb`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
config := new(startConfig)
|
config := MustNewConfig(viper.GetViper())
|
||||||
err := viper.Unmarshal(config, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
|
masterKey, _ := cmd.Flags().GetString(flagMasterKey)
|
||||||
mapstructure.StringToTimeDurationHookFunc(),
|
|
||||||
mapstructure.StringToSliceHookFunc(":"),
|
|
||||||
)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = config.Log.SetLogger()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
masterKey, _ := cmd.Flags().GetString("masterkey")
|
|
||||||
return startZitadel(config, masterKey)
|
return startZitadel(config, masterKey)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
bindUint16Flag(start, "port", "port to run ZITADEL on")
|
|
||||||
bindStringFlag(start, "externalDomain", "domain ZITADEL will be exposed on")
|
|
||||||
bindStringFlag(start, "externalPort", "port ZITADEL will be exposed on")
|
|
||||||
bindBoolFlag(start, "externalSecure", "if ZITADEL will be served on HTTPS")
|
|
||||||
|
|
||||||
start.PersistentFlags().String(flagMasterKey, "", "masterkey for en/decryption keys")
|
startFlags(start)
|
||||||
|
|
||||||
return start
|
return start
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindStringFlag(cmd *cobra.Command, name, description string) {
|
func startZitadel(config *Config, masterKey string) error {
|
||||||
cmd.PersistentFlags().String(name, viper.GetString(name), description)
|
|
||||||
viper.BindPFlag(name, cmd.PersistentFlags().Lookup(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindUint16Flag(cmd *cobra.Command, name, description string) {
|
|
||||||
cmd.PersistentFlags().Uint16(name, uint16(viper.GetUint(name)), description)
|
|
||||||
viper.BindPFlag(name, cmd.PersistentFlags().Lookup(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindBoolFlag(cmd *cobra.Command, name, description string) {
|
|
||||||
cmd.PersistentFlags().Bool(name, viper.GetBool(name), description)
|
|
||||||
viper.BindPFlag(name, cmd.PersistentFlags().Lookup(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
type startConfig struct {
|
|
||||||
Log *logging.Config
|
|
||||||
Port uint16
|
|
||||||
ExternalPort uint16
|
|
||||||
ExternalDomain string
|
|
||||||
ExternalSecure bool
|
|
||||||
Database database.Config
|
|
||||||
Projections projection.Config
|
|
||||||
AuthZ authz.Config
|
|
||||||
Auth auth_es.Config
|
|
||||||
Admin admin_es.Config
|
|
||||||
UserAgentCookie *middleware.UserAgentCookieConfig
|
|
||||||
OIDC oidc.Config
|
|
||||||
Login login.Config
|
|
||||||
Console console.Config
|
|
||||||
Notification notification.Config
|
|
||||||
AssetStorage static_config.AssetStorageConfig
|
|
||||||
InternalAuthZ internal_authz.Config
|
|
||||||
SystemDefaults systemdefaults.SystemDefaults
|
|
||||||
EncryptionKeys *encryptionKeyConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
type encryptionKeyConfig struct {
|
|
||||||
DomainVerification *crypto.KeyConfig
|
|
||||||
IDPConfig *crypto.KeyConfig
|
|
||||||
OIDC *crypto.KeyConfig
|
|
||||||
OTP *crypto.KeyConfig
|
|
||||||
SMS *crypto.KeyConfig
|
|
||||||
SMTP *crypto.KeyConfig
|
|
||||||
User *crypto.KeyConfig
|
|
||||||
CSRFCookieKeyID string
|
|
||||||
UserAgentCookieKeyID string
|
|
||||||
}
|
|
||||||
|
|
||||||
func startZitadel(config *startConfig, masterKey string) error {
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
keyChan := make(chan interface{})
|
keyChan := make(chan interface{})
|
||||||
|
|
||||||
@ -197,7 +129,7 @@ func startZitadel(config *startConfig, masterKey string) error {
|
|||||||
return listen(ctx, router, config.Port)
|
return listen(ctx, router, config.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startAPIs(ctx context.Context, router *mux.Router, commands *command.Commands, queries *query.Queries, eventstore *eventstore.Eventstore, dbClient *sql.DB, keyChan chan interface{}, config *startConfig, store static.Storage, authZRepo authz_repo.Repository, keys *encryptionKeys) error {
|
func startAPIs(ctx context.Context, router *mux.Router, commands *command.Commands, queries *query.Queries, eventstore *eventstore.Eventstore, dbClient *sql.DB, keyChan chan interface{}, config *Config, store static.Storage, authZRepo authz_repo.Repository, keys *encryptionKeys) error {
|
||||||
repo := struct {
|
repo := struct {
|
||||||
authz_repo.Repository
|
authz_repo.Repository
|
||||||
*query.Queries
|
*query.Queries
|
||||||
|
40
cmd/admin/start/start_from_init.go
Normal file
40
cmd/admin/start/start_from_init.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package start
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/cmd/admin/initialise"
|
||||||
|
"github.com/caos/zitadel/cmd/admin/setup"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewStartFromInit() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "start-from-init",
|
||||||
|
Short: "cold starts zitadel",
|
||||||
|
Long: `cold starts ZITADEL.
|
||||||
|
First the minimum requirements to start ZITADEL are set up.
|
||||||
|
Second the initial events are created.
|
||||||
|
Last ZITADEL starts.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- cockroachdb`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
initialise.InitAll(initialise.MustNewConfig(viper.GetViper()))
|
||||||
|
|
||||||
|
setupConfig := setup.MustNewConfig(viper.GetViper())
|
||||||
|
setupSteps := setup.MustNewSteps(viper.New())
|
||||||
|
setup.Setup(setupConfig, setupSteps)
|
||||||
|
|
||||||
|
startConfig := MustNewConfig(viper.GetViper())
|
||||||
|
startMasterKey, _ := cmd.Flags().GetString(flagMasterKey)
|
||||||
|
|
||||||
|
err := startZitadel(startConfig, startMasterKey)
|
||||||
|
logging.OnError(err).Fatal("unable to start zitadel")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
startFlags(cmd)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
@ -35,15 +35,14 @@ AdminUser:
|
|||||||
Key: ""
|
Key: ""
|
||||||
|
|
||||||
Projections:
|
Projections:
|
||||||
Config:
|
RequeueEvery: 10s
|
||||||
RequeueEvery: 10s
|
RetryFailedAfter: 1s
|
||||||
RetryFailedAfter: 1s
|
MaxFailureCount: 5
|
||||||
MaxFailureCount: 5
|
BulkLimit: 200
|
||||||
BulkLimit: 200
|
MaxIterators: 1
|
||||||
MaxIterators: 1
|
Customizations:
|
||||||
Customizations:
|
projects:
|
||||||
projects:
|
BulkLimit: 2000
|
||||||
BulkLimit: 2000
|
|
||||||
|
|
||||||
AuthZ:
|
AuthZ:
|
||||||
Repository:
|
Repository:
|
||||||
|
@ -4865,7 +4865,7 @@ This is an empty request
|
|||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| policy | zitadel.policy.v1.DomainPolicy | - | |
|
| policy | zitadel.policy.v1.OrgIAMPolicy | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,6 +121,10 @@ func GetInstance(ctx context.Context) Instance {
|
|||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithInstance(ctx context.Context, instance Instance) context.Context {
|
||||||
|
return context.WithValue(ctx, instanceKey, instance)
|
||||||
|
}
|
||||||
|
|
||||||
func GetRequestPermissionsFromCtx(ctx context.Context) []string {
|
func GetRequestPermissionsFromCtx(ctx context.Context) []string {
|
||||||
ctxPermission, _ := ctx.Value(requestPermissionsKey).([]string)
|
ctxPermission, _ := ctx.Value(requestPermissionsKey).([]string)
|
||||||
return ctxPermission
|
return ctxPermission
|
||||||
|
@ -26,64 +26,6 @@ func (s *Server) GetCustomDomainPolicy(ctx context.Context, req *admin_pb.GetCus
|
|||||||
return &admin_pb.GetCustomDomainPolicyResponse{Policy: policy_grpc.DomainPolicyToPb(policy)}, nil
|
return &admin_pb.GetCustomDomainPolicyResponse{Policy: policy_grpc.DomainPolicyToPb(policy)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.AddCustomOrgIAMPolicyRequest) (*admin_pb.AddCustomOrgIAMPolicyResponse, error) {
|
|
||||||
policy, err := s.command.AddOrgDomainPolicy(ctx, req.OrgId, domainPolicyToDomain(req.UserLoginMustBeDomain))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &admin_pb.AddCustomOrgIAMPolicyResponse{
|
|
||||||
Details: object.AddToDetailsPb(
|
|
||||||
policy.Sequence,
|
|
||||||
policy.ChangeDate,
|
|
||||||
policy.ResourceOwner,
|
|
||||||
),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) UpdateOrgIAMPolicy(ctx context.Context, req *admin_pb.UpdateOrgIAMPolicyRequest) (*admin_pb.UpdateOrgIAMPolicyResponse, error) {
|
|
||||||
config, err := s.command.ChangeDefaultDomainPolicy(ctx, updateOrgIAMPolicyToDomain(req))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &admin_pb.UpdateOrgIAMPolicyResponse{
|
|
||||||
Details: object.ChangeToDetailsPb(
|
|
||||||
config.Sequence,
|
|
||||||
config.ChangeDate,
|
|
||||||
config.ResourceOwner,
|
|
||||||
),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) UpdateCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.UpdateCustomOrgIAMPolicyRequest) (*admin_pb.UpdateCustomOrgIAMPolicyResponse, error) {
|
|
||||||
config, err := s.command.ChangeOrgDomainPolicy(ctx, req.OrgId, updateCustomOrgIAMPolicyToDomain(req))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &admin_pb.UpdateCustomOrgIAMPolicyResponse{
|
|
||||||
Details: object.ChangeToDetailsPb(
|
|
||||||
config.Sequence,
|
|
||||||
config.ChangeDate,
|
|
||||||
config.ResourceOwner,
|
|
||||||
),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) GetOrgIAMPolicy(ctx context.Context, _ *admin_pb.GetOrgIAMPolicyRequest) (*admin_pb.GetOrgIAMPolicyResponse, error) {
|
|
||||||
policy, err := s.query.DefaultDomainPolicy(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &admin_pb.GetOrgIAMPolicyResponse{Policy: policy_grpc.DomainPolicyToOrgIAMPb(policy)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) GetCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.GetCustomOrgIAMPolicyRequest) (*admin_pb.GetCustomOrgIAMPolicyResponse, error) {
|
|
||||||
policy, err := s.query.DomainPolicyByOrg(ctx, req.OrgId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &admin_pb.GetCustomOrgIAMPolicyResponse{Policy: policy_grpc.DomainPolicyToOrgIAMPb(policy)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) AddCustomDomainPolicy(ctx context.Context, req *admin_pb.AddCustomDomainPolicyRequest) (*admin_pb.AddCustomDomainPolicyResponse, error) {
|
func (s *Server) AddCustomDomainPolicy(ctx context.Context, req *admin_pb.AddCustomDomainPolicyRequest) (*admin_pb.AddCustomDomainPolicyResponse, error) {
|
||||||
policy, err := s.command.AddOrgDomainPolicy(ctx, req.OrgId, domainPolicyToDomain(req.UserLoginMustBeDomain))
|
policy, err := s.command.AddOrgDomainPolicy(ctx, req.OrgId, domainPolicyToDomain(req.UserLoginMustBeDomain))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -158,6 +100,64 @@ func updateCustomDomainPolicyToDomain(req *admin_pb.UpdateCustomDomainPolicyRequ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) AddCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.AddCustomOrgIAMPolicyRequest) (*admin_pb.AddCustomOrgIAMPolicyResponse, error) {
|
||||||
|
policy, err := s.command.AddOrgDomainPolicy(ctx, req.OrgId, domainPolicyToDomain(req.UserLoginMustBeDomain))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &admin_pb.AddCustomOrgIAMPolicyResponse{
|
||||||
|
Details: object.AddToDetailsPb(
|
||||||
|
policy.Sequence,
|
||||||
|
policy.ChangeDate,
|
||||||
|
policy.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) UpdateOrgIAMPolicy(ctx context.Context, req *admin_pb.UpdateOrgIAMPolicyRequest) (*admin_pb.UpdateOrgIAMPolicyResponse, error) {
|
||||||
|
config, err := s.command.ChangeDefaultDomainPolicy(ctx, updateOrgIAMPolicyToDomain(req))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &admin_pb.UpdateOrgIAMPolicyResponse{
|
||||||
|
Details: object.ChangeToDetailsPb(
|
||||||
|
config.Sequence,
|
||||||
|
config.ChangeDate,
|
||||||
|
config.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) UpdateCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.UpdateCustomOrgIAMPolicyRequest) (*admin_pb.UpdateCustomOrgIAMPolicyResponse, error) {
|
||||||
|
config, err := s.command.ChangeOrgDomainPolicy(ctx, req.OrgId, updateCustomOrgIAMPolicyToDomain(req))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &admin_pb.UpdateCustomOrgIAMPolicyResponse{
|
||||||
|
Details: object.ChangeToDetailsPb(
|
||||||
|
config.Sequence,
|
||||||
|
config.ChangeDate,
|
||||||
|
config.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetOrgIAMPolicy(ctx context.Context, _ *admin_pb.GetOrgIAMPolicyRequest) (*admin_pb.GetOrgIAMPolicyResponse, error) {
|
||||||
|
policy, err := s.query.DefaultDomainPolicy(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &admin_pb.GetOrgIAMPolicyResponse{Policy: policy_grpc.DomainPolicyToOrgIAMPb(policy)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.GetCustomOrgIAMPolicyRequest) (*admin_pb.GetCustomOrgIAMPolicyResponse, error) {
|
||||||
|
policy, err := s.query.DomainPolicyByOrg(ctx, req.OrgId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &admin_pb.GetCustomOrgIAMPolicyResponse{Policy: policy_grpc.DomainPolicyToOrgIAMPb(policy)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func updateOrgIAMPolicyToDomain(req *admin_pb.UpdateOrgIAMPolicyRequest) *domain.DomainPolicy {
|
func updateOrgIAMPolicyToDomain(req *admin_pb.UpdateOrgIAMPolicyRequest) *domain.DomainPolicy {
|
||||||
return &domain.DomainPolicy{
|
return &domain.DomainPolicy{
|
||||||
UserLoginMustBeDomain: req.UserLoginMustBeDomain,
|
UserLoginMustBeDomain: req.UserLoginMustBeDomain,
|
||||||
|
@ -112,6 +112,16 @@ func (s *Server) GetDomainPolicy(ctx context.Context, req *mgmt_pb.GetDomainPoli
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetOrgIAMPolicy(ctx context.Context, _ *mgmt_pb.GetOrgIAMPolicyRequest) (*mgmt_pb.GetOrgIAMPolicyResponse, error) {
|
||||||
|
policy, err := s.query.DomainPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &mgmt_pb.GetOrgIAMPolicyResponse{
|
||||||
|
Policy: policy_grpc.DomainPolicyToOrgIAMPb(policy),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) ListOrgDomains(ctx context.Context, req *mgmt_pb.ListOrgDomainsRequest) (*mgmt_pb.ListOrgDomainsResponse, error) {
|
func (s *Server) ListOrgDomains(ctx context.Context, req *mgmt_pb.ListOrgDomainsRequest) (*mgmt_pb.ListOrgDomainsResponse, error) {
|
||||||
queries, err := ListOrgDomainsRequestToModel(req)
|
queries, err := ListOrgDomainsRequestToModel(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,7 +100,7 @@ func NewProvider(ctx context.Context, config Config, issuer, defaultLogoutRedire
|
|||||||
options...,
|
options...,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowInternal(err, "OIDC-DAtg3", "cannot create provider: %w")
|
return nil, caos_errs.ThrowInternal(err, "OIDC-DAtg3", "cannot create provider")
|
||||||
}
|
}
|
||||||
return provider, nil
|
return provider, nil
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||||
@ -69,3 +71,7 @@ func (h *handler) LockDuration() time.Duration {
|
|||||||
func (h *handler) QueryLimit() uint64 {
|
func (h *handler) QueryLimit() uint64 {
|
||||||
return h.bulkLimit
|
return h.bulkLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withInstanceID(ctx context.Context, instanceID string) context.Context {
|
||||||
|
return authz.WithInstance(ctx, authz.Instance{ID: instanceID})
|
||||||
|
}
|
||||||
|
@ -121,9 +121,9 @@ func (i *IDPProvider) processIdpProvider(event *es_models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
config := new(query2.IDP)
|
config := new(query2.IDP)
|
||||||
if event.AggregateID == domain.IAMID {
|
if event.AggregateID == domain.IAMID {
|
||||||
config, err = i.getDefaultIDPConfig(context.TODO(), esConfig.IDPConfigID)
|
config, err = i.getDefaultIDPConfig(event.InstanceID, esConfig.IDPConfigID)
|
||||||
} else {
|
} else {
|
||||||
config, err = i.getOrgIDPConfig(context.TODO(), event.AggregateID, esConfig.IDPConfigID)
|
config, err = i.getOrgIDPConfig(event.InstanceID, event.AggregateID, esConfig.IDPConfigID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -146,9 +146,9 @@ func (i *IDPProvider) processIdpProvider(event *es_models.Event) (err error) {
|
|||||||
func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
|
func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
|
||||||
var config *query2.IDP
|
var config *query2.IDP
|
||||||
if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) {
|
if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) {
|
||||||
config, err = i.getDefaultIDPConfig(context.Background(), provider.IDPConfigID)
|
config, err = i.getDefaultIDPConfig(provider.InstanceID, provider.IDPConfigID)
|
||||||
} else {
|
} else {
|
||||||
config, err = i.getOrgIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
|
config, err = i.getOrgIDPConfig(provider.InstanceID, provider.AggregateID, provider.IDPConfigID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -186,10 +186,10 @@ func (i *IDPProvider) OnSuccess() error {
|
|||||||
return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp)
|
return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPProvider) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*query2.IDP, error) {
|
func (i *IDPProvider) getOrgIDPConfig(instanceID, aggregateID, idpConfigID string) (*query2.IDP, error) {
|
||||||
return i.queries.IDPByIDAndResourceOwner(ctx, idpConfigID, aggregateID)
|
return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), idpConfigID, aggregateID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *IDPProvider) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*query2.IDP, error) {
|
func (u *IDPProvider) getDefaultIDPConfig(instanceID, idpConfigID string) (*query2.IDP, error) {
|
||||||
return u.queries.IDPByIDAndResourceOwner(ctx, idpConfigID, domain.IAMID)
|
return u.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), idpConfigID, domain.IAMID)
|
||||||
}
|
}
|
||||||
|
@ -187,9 +187,9 @@ func (u *User) ProcessOrg(event *es_models.Event) (err error) {
|
|||||||
switch event.Type {
|
switch event.Type {
|
||||||
case org_es_model.OrgDomainVerified,
|
case org_es_model.OrgDomainVerified,
|
||||||
org_es_model.OrgDomainRemoved,
|
org_es_model.OrgDomainRemoved,
|
||||||
es_models.EventType(org.OrgDomainPolicyAddedEventType),
|
es_models.EventType(org.DomainPolicyAddedEventType),
|
||||||
es_models.EventType(org.OrgDomainPolicyChangedEventType),
|
es_models.EventType(org.DomainPolicyChangedEventType),
|
||||||
es_models.EventType(org.OrgDomainPolicyRemovedEventType):
|
es_models.EventType(org.DomainPolicyRemovedEventType):
|
||||||
return u.fillLoginNamesOnOrgUsers(event)
|
return u.fillLoginNamesOnOrgUsers(event)
|
||||||
case org_es_model.OrgDomainPrimarySet:
|
case org_es_model.OrgDomainPrimarySet:
|
||||||
return u.fillPreferredLoginNamesOnOrgUsers(event)
|
return u.fillPreferredLoginNamesOnOrgUsers(event)
|
||||||
@ -268,7 +268,7 @@ func (u *User) loginNameInformation(ctx context.Context, orgID string) (userLogi
|
|||||||
return false, "", nil, err
|
return false, "", nil, err
|
||||||
}
|
}
|
||||||
if org.DomainPolicy == nil {
|
if org.DomainPolicy == nil {
|
||||||
policy, err := u.queries.DefaultDomainPolicy(ctx)
|
policy, err := u.queries.DefaultDomainPolicy(withInstanceID(ctx, org.InstanceID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", nil, err
|
return false, "", nil, err
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||||
@ -137,9 +138,9 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if event.AggregateType == iam_es_model.IAMAggregate {
|
if event.AggregateType == iam_es_model.IAMAggregate {
|
||||||
config, err = i.getDefaultIDPConfig(context.Background(), configView.IDPConfigID)
|
config, err = i.getDefaultIDPConfig(event.InstanceID, configView.IDPConfigID)
|
||||||
} else {
|
} else {
|
||||||
config, err = i.getOrgIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
|
config, err = i.getOrgIDPConfig(event.InstanceID, event.AggregateID, configView.IDPConfigID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -155,9 +156,9 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
|
func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
|
||||||
config, err := i.getOrgIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
|
config, err := i.getOrgIDPConfig(externalIDP.InstanceID, externalIDP.ResourceOwner, externalIDP.IDPConfigID)
|
||||||
if caos_errs.IsNotFound(err) {
|
if caos_errs.IsNotFound(err) {
|
||||||
config, err = i.getDefaultIDPConfig(context.Background(), externalIDP.IDPConfigID)
|
config, err = i.getDefaultIDPConfig(externalIDP.InstanceID, externalIDP.IDPConfigID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -179,10 +180,10 @@ func (i *ExternalIDP) OnSuccess() error {
|
|||||||
return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
|
return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ExternalIDP) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*query2.IDP, error) {
|
func (i *ExternalIDP) getOrgIDPConfig(instanceID, aggregateID, idpConfigID string) (*query2.IDP, error) {
|
||||||
return i.queries.IDPByIDAndResourceOwner(ctx, idpConfigID, aggregateID)
|
return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), idpConfigID, aggregateID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ExternalIDP) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*query2.IDP, error) {
|
func (i *ExternalIDP) getDefaultIDPConfig(instanceID, idpConfigID string) (*query2.IDP, error) {
|
||||||
return i.queries.IDPByIDAndResourceOwner(ctx, idpConfigID, domain.IAMID)
|
return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), idpConfigID, domain.IAMID)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/id"
|
"github.com/caos/zitadel/internal/id"
|
||||||
"github.com/caos/zitadel/internal/repository/action"
|
"github.com/caos/zitadel/internal/repository/action"
|
||||||
iam_repo "github.com/caos/zitadel/internal/repository/instance"
|
instance_repo "github.com/caos/zitadel/internal/repository/instance"
|
||||||
"github.com/caos/zitadel/internal/repository/keypair"
|
"github.com/caos/zitadel/internal/repository/keypair"
|
||||||
"github.com/caos/zitadel/internal/repository/org"
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
proj_repo "github.com/caos/zitadel/internal/repository/project"
|
proj_repo "github.com/caos/zitadel/internal/repository/project"
|
||||||
@ -82,7 +82,7 @@ func StartCommands(es *eventstore.Eventstore,
|
|||||||
domainVerificationAlg: domainVerificationEncryption,
|
domainVerificationAlg: domainVerificationEncryption,
|
||||||
keyAlgorithm: oidcEncryption,
|
keyAlgorithm: oidcEncryption,
|
||||||
}
|
}
|
||||||
iam_repo.RegisterEventMappers(repo.eventstore)
|
instance_repo.RegisterEventMappers(repo.eventstore)
|
||||||
org.RegisterEventMappers(repo.eventstore)
|
org.RegisterEventMappers(repo.eventstore)
|
||||||
usr_repo.RegisterEventMappers(repo.eventstore)
|
usr_repo.RegisterEventMappers(repo.eventstore)
|
||||||
usr_grant_repo.RegisterEventMappers(repo.eventstore)
|
usr_grant_repo.RegisterEventMappers(repo.eventstore)
|
||||||
|
@ -27,7 +27,7 @@ func (c *Commands) SetDefaultMessageText(ctx context.Context, messageText *domai
|
|||||||
return writeModelToObjectDetails(&existingMessageText.WriteModel), nil
|
return writeModelToObjectDetails(&existingMessageText.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) setDefaultMessageText(ctx context.Context, instanceAgg *eventstore.Aggregate, msg *domain.CustomMessageText) ([]eventstore.Command, *InstanceCustomMessageTextReadModel, error) {
|
func (c *Commands) setDefaultMessageText(ctx context.Context, instanceAgg *eventstore.Aggregate, msg *domain.CustomMessageText) ([]eventstore.Command, *InstanceCustomMessageTextWriteModel, error) {
|
||||||
if !msg.IsValid() {
|
if !msg.IsValid() {
|
||||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-kd9fs", "Errors.CustomMessageText.Invalid")
|
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-kd9fs", "Errors.CustomMessageText.Invalid")
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ func (c *Commands) RemoveInstanceMessageTexts(ctx context.Context, messageTextTy
|
|||||||
return writeModelToObjectDetails(&customText.WriteModel), nil
|
return writeModelToObjectDetails(&customText.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) defaultCustomMessageTextWriteModelByID(ctx context.Context, messageType string, lang language.Tag) (*InstanceCustomMessageTextReadModel, error) {
|
func (c *Commands) defaultCustomMessageTextWriteModelByID(ctx context.Context, messageType string, lang language.Tag) (*InstanceCustomMessageTextWriteModel, error) {
|
||||||
writeModel := NewInstanceCustomMessageTextWriteModel(messageType, lang)
|
writeModel := NewInstanceCustomMessageTextWriteModel(messageType, lang)
|
||||||
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -8,12 +8,12 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/instance"
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InstanceCustomMessageTextReadModel struct {
|
type InstanceCustomMessageTextWriteModel struct {
|
||||||
CustomMessageTextReadModel
|
CustomMessageTextReadModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstanceCustomMessageTextWriteModel(messageTextType string, lang language.Tag) *InstanceCustomMessageTextReadModel {
|
func NewInstanceCustomMessageTextWriteModel(messageTextType string, lang language.Tag) *InstanceCustomMessageTextWriteModel {
|
||||||
return &InstanceCustomMessageTextReadModel{
|
return &InstanceCustomMessageTextWriteModel{
|
||||||
CustomMessageTextReadModel{
|
CustomMessageTextReadModel{
|
||||||
WriteModel: eventstore.WriteModel{
|
WriteModel: eventstore.WriteModel{
|
||||||
AggregateID: domain.IAMID,
|
AggregateID: domain.IAMID,
|
||||||
@ -25,7 +25,7 @@ func NewInstanceCustomMessageTextWriteModel(messageTextType string, lang languag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *InstanceCustomMessageTextReadModel) AppendEvents(events ...eventstore.Event) {
|
func (wm *InstanceCustomMessageTextWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *instance.CustomTextSetEvent:
|
case *instance.CustomTextSetEvent:
|
||||||
@ -38,11 +38,11 @@ func (wm *InstanceCustomMessageTextReadModel) AppendEvents(events ...eventstore.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *InstanceCustomMessageTextReadModel) Reduce() error {
|
func (wm *InstanceCustomMessageTextWriteModel) Reduce() error {
|
||||||
return wm.CustomMessageTextReadModel.Reduce()
|
return wm.CustomMessageTextReadModel.Reduce()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *InstanceCustomMessageTextReadModel) Query() *eventstore.SearchQueryBuilder {
|
func (wm *InstanceCustomMessageTextWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||||
ResourceOwner(wm.ResourceOwner).
|
ResourceOwner(wm.ResourceOwner).
|
||||||
AddQuery().
|
AddQuery().
|
||||||
|
@ -37,7 +37,7 @@ func (c *Commands) addDefaultDomainPolicy(ctx context.Context, instanceAgg *even
|
|||||||
if addedPolicy.State == domain.PolicyStateActive {
|
if addedPolicy.State == domain.PolicyStateActive {
|
||||||
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.IAM.DomainPolicy.AlreadyExists")
|
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.IAM.DomainPolicy.AlreadyExists")
|
||||||
}
|
}
|
||||||
return iam_repo.NewInstnaceDomainPolicyAddedEvent(ctx, instanceAgg, policy.UserLoginMustBeDomain), nil
|
return iam_repo.NewDomainPolicyAddedEvent(ctx, instanceAgg, policy.UserLoginMustBeDomain), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) ChangeDefaultDomainPolicy(ctx context.Context, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) {
|
func (c *Commands) ChangeDefaultDomainPolicy(ctx context.Context, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) {
|
||||||
|
@ -28,9 +28,9 @@ func NewInstanceDomainPolicyWriteModel() *InstanceDomainPolicyWriteModel {
|
|||||||
func (wm *InstanceDomainPolicyWriteModel) AppendEvents(events ...eventstore.Event) {
|
func (wm *InstanceDomainPolicyWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *instance.InstanceDomainPolicyAddedEvent:
|
case *instance.DomainPolicyAddedEvent:
|
||||||
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyAddedEvent)
|
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyAddedEvent)
|
||||||
case *instance.InstanceDomainPolicyChangedEvent:
|
case *instance.DomainPolicyChangedEvent:
|
||||||
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyChangedEvent)
|
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyChangedEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,15 +47,15 @@ func (wm *InstanceDomainPolicyWriteModel) Query() *eventstore.SearchQueryBuilder
|
|||||||
AggregateTypes(instance.AggregateType).
|
AggregateTypes(instance.AggregateType).
|
||||||
AggregateIDs(wm.PolicyDomainWriteModel.AggregateID).
|
AggregateIDs(wm.PolicyDomainWriteModel.AggregateID).
|
||||||
EventTypes(
|
EventTypes(
|
||||||
instance.InstanceDomainPolicyAddedEventType,
|
instance.DomainPolicyAddedEventType,
|
||||||
instance.InstanceDomainPolicyChangedEventType).
|
instance.DomainPolicyChangedEventType).
|
||||||
Builder()
|
Builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *InstanceDomainPolicyWriteModel) NewChangedEvent(
|
func (wm *InstanceDomainPolicyWriteModel) NewChangedEvent(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
userLoginMustBeDomain bool) (*instance.InstanceDomainPolicyChangedEvent, bool) {
|
userLoginMustBeDomain bool) (*instance.DomainPolicyChangedEvent, bool) {
|
||||||
changes := make([]policy.OrgPolicyChanges, 0)
|
changes := make([]policy.OrgPolicyChanges, 0)
|
||||||
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
|
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
|
||||||
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
|
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
|
||||||
@ -63,7 +63,7 @@ func (wm *InstanceDomainPolicyWriteModel) NewChangedEvent(
|
|||||||
if len(changes) == 0 {
|
if len(changes) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
changedEvent, err := instance.NewInstanceDomainPolicyChangedEvent(ctx, aggregate, changes)
|
changedEvent, err := instance.NewDomainPolicyChangedEvent(ctx, aggregate, changes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,13 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
|
|||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "orgiam policy already existing, already exists error",
|
name: "domain policy already existing, already exists error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: eventstoreExpect(
|
||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate().Aggregate,
|
&instance.NewAggregate().Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -66,7 +66,7 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate().Aggregate,
|
&instance.NewAggregate().Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -111,7 +111,7 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommandSide_ChangeDefaultOrgIAMPolicy(t *testing.T) {
|
func TestCommandSide_ChangeDefaultDomainPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ func TestCommandSide_ChangeDefaultOrgIAMPolicy(t *testing.T) {
|
|||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "orgiampolicy not existing, not found error",
|
name: "domain policy not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: eventstoreExpect(
|
||||||
t,
|
t,
|
||||||
@ -154,7 +154,7 @@ func TestCommandSide_ChangeDefaultOrgIAMPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate().Aggregate,
|
&instance.NewAggregate().Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -179,7 +179,7 @@ func TestCommandSide_ChangeDefaultOrgIAMPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate().Aggregate,
|
&instance.NewAggregate().Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -188,7 +188,7 @@ func TestCommandSide_ChangeDefaultOrgIAMPolicy(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
newDefaultOrgIAMPolicyChangedEvent(context.Background(), false),
|
newDefaultDomainPolicyChangedEvent(context.Background(), false),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -230,8 +230,8 @@ func TestCommandSide_ChangeDefaultOrgIAMPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDefaultOrgIAMPolicyChangedEvent(ctx context.Context, userLoginMustBeDomain bool) *instance.InstanceDomainPolicyChangedEvent {
|
func newDefaultDomainPolicyChangedEvent(ctx context.Context, userLoginMustBeDomain bool) *instance.DomainPolicyChangedEvent {
|
||||||
event, _ := instance.NewInstanceDomainPolicyChangedEvent(ctx,
|
event, _ := instance.NewDomainPolicyChangedEvent(ctx,
|
||||||
&instance.NewAggregate().Aggregate,
|
&instance.NewAggregate().Aggregate,
|
||||||
[]policy.OrgPolicyChanges{
|
[]policy.OrgPolicyChanges{
|
||||||
policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain),
|
policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain),
|
||||||
|
@ -32,19 +32,20 @@ func (c *Commands) checkOrgExists(ctx context.Context, orgID string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) SetUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, claimedUserIDs []string, selfregistered bool) (*domain.ObjectDetails, error) {
|
func (c *Commands) SetUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human, initCodeGenerator, phoneCodeGenerator crypto.Generator, claimedUserIDs []string, selfregistered bool) (*domain.ObjectDetails, error) {
|
||||||
orgIAMPolicy, err := c.getDefaultDomainPolicy(ctx)
|
domainPolicy, err := c.getDefaultDomainPolicy(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.IAM.DomainPolicy.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.Instance.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
pwPolicy, err := c.getDefaultPasswordComplexityPolicy(ctx)
|
pwPolicy, err := c.getDefaultPasswordComplexityPolicy(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.IAM.PasswordComplexity.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Instance.PasswordComplexity.NotFound")
|
||||||
}
|
}
|
||||||
_, orgWriteModel, _, _, events, err := c.setUpOrg(ctx, organisation, admin, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, claimedUserIDs, selfregistered)
|
_, orgWriteModel, _, _, events, err := c.setUpOrg(ctx, organisation, admin, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, claimedUserIDs, selfregistered)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -201,7 +202,7 @@ func (c *Commands) setUpOrg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) addOrg(ctx context.Context, organisation *domain.Org, claimedUserIDs []string) (_ *eventstore.Aggregate, _ *OrgWriteModel, _ []eventstore.Command, err error) {
|
func (c *Commands) addOrg(ctx context.Context, organisation *domain.Org, claimedUserIDs []string) (_ *eventstore.Aggregate, _ *OrgWriteModel, _ []eventstore.Command, err error) {
|
||||||
if organisation == nil || !organisation.IsValid() {
|
if !organisation.IsValid() {
|
||||||
return nil, nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMM-deLSk", "Errors.Org.Invalid")
|
return nil, nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMM-deLSk", "Errors.Org.Invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +221,8 @@ func (c *Commands) addOrg(ctx context.Context, organisation *domain.Org, claimed
|
|||||||
orgDomainEvents, err := c.addOrgDomain(ctx, orgAgg, NewOrgDomainWriteModel(orgAgg.ID, orgDomain.Domain), orgDomain, claimedUserIDs)
|
orgDomainEvents, err := c.addOrgDomain(ctx, orgAgg, NewOrgDomainWriteModel(orgAgg.ID, orgDomain.Domain), orgDomain, claimedUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
} else {
|
|
||||||
events = append(events, orgDomainEvents...)
|
|
||||||
}
|
}
|
||||||
|
events = append(events, orgDomainEvents...)
|
||||||
}
|
}
|
||||||
return orgAgg, addedOrg, events, nil
|
return orgAgg, addedOrg, events, nil
|
||||||
}
|
}
|
||||||
|
@ -819,7 +819,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
|||||||
),
|
),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org2", "org2").Aggregate,
|
&org.NewAggregate("org2", "org2").Aggregate,
|
||||||
false))),
|
false))),
|
||||||
expectPush(
|
expectPush(
|
||||||
|
@ -39,7 +39,7 @@ func (c *Commands) addOrgDomainPolicy(ctx context.Context, orgAgg *eventstore.Ag
|
|||||||
if addedPolicy.State == domain.PolicyStateActive {
|
if addedPolicy.State == domain.PolicyStateActive {
|
||||||
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-1M8ds", "Errors.Org.DomainPolicy.AlreadyExists")
|
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-1M8ds", "Errors.Org.DomainPolicy.AlreadyExists")
|
||||||
}
|
}
|
||||||
return org.NewOrgDomainPolicyAddedEvent(ctx, orgAgg, policy.UserLoginMustBeDomain), nil
|
return org.NewDomainPolicyAddedEvent(ctx, orgAgg, policy.UserLoginMustBeDomain), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) ChangeOrgDomainPolicy(ctx context.Context, resourceOwner string, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) {
|
func (c *Commands) ChangeOrgDomainPolicy(ctx context.Context, resourceOwner string, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) {
|
||||||
@ -80,11 +80,11 @@ func (c *Commands) RemoveOrgDomainPolicy(ctx context.Context, orgID string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.OrgIAMPolicy.NotFound")
|
return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyDomainWriteModel.WriteModel)
|
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyDomainWriteModel.WriteModel)
|
||||||
_, err = c.eventstore.Push(ctx, org.NewOrgDomainPolicyRemovedEvent(ctx, orgAgg))
|
_, err = c.eventstore.Push(ctx, org.NewDomainPolicyRemovedEvent(ctx, orgAgg))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,11 +27,11 @@ func NewOrgDomainPolicyWriteModel(orgID string) *OrgDomainPolicyWriteModel {
|
|||||||
func (wm *OrgDomainPolicyWriteModel) AppendEvents(events ...eventstore.Event) {
|
func (wm *OrgDomainPolicyWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *org.OrgDomainPolicyAddedEvent:
|
case *org.DomainPolicyAddedEvent:
|
||||||
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyAddedEvent)
|
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyAddedEvent)
|
||||||
case *org.OrgDomainPolicyChangedEvent:
|
case *org.DomainPolicyChangedEvent:
|
||||||
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyChangedEvent)
|
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyChangedEvent)
|
||||||
case *org.OrgDomainPolicyRemovedEvent:
|
case *org.DomainPolicyRemovedEvent:
|
||||||
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyRemovedEvent)
|
wm.PolicyDomainWriteModel.AppendEvents(&e.DomainPolicyRemovedEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,16 +47,16 @@ func (wm *OrgDomainPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
AddQuery().
|
AddQuery().
|
||||||
AggregateTypes(org.AggregateType).
|
AggregateTypes(org.AggregateType).
|
||||||
AggregateIDs(wm.PolicyDomainWriteModel.AggregateID).
|
AggregateIDs(wm.PolicyDomainWriteModel.AggregateID).
|
||||||
EventTypes(org.OrgDomainPolicyAddedEventType,
|
EventTypes(org.DomainPolicyAddedEventType,
|
||||||
org.OrgDomainPolicyChangedEventType,
|
org.DomainPolicyChangedEventType,
|
||||||
org.OrgDomainPolicyRemovedEventType).
|
org.DomainPolicyRemovedEventType).
|
||||||
Builder()
|
Builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *OrgDomainPolicyWriteModel) NewChangedEvent(
|
func (wm *OrgDomainPolicyWriteModel) NewChangedEvent(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
userLoginMustBeDomain bool) (*org.OrgDomainPolicyChangedEvent, bool) {
|
userLoginMustBeDomain bool) (*org.DomainPolicyChangedEvent, bool) {
|
||||||
changes := make([]policy.OrgPolicyChanges, 0)
|
changes := make([]policy.OrgPolicyChanges, 0)
|
||||||
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
|
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
|
||||||
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
|
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
|
||||||
@ -64,7 +64,7 @@ func (wm *OrgDomainPolicyWriteModel) NewChangedEvent(
|
|||||||
if len(changes) == 0 {
|
if len(changes) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
changedEvent, err := org.NewOrgDomainPolicyChangedEvent(ctx, aggregate, changes)
|
changedEvent, err := org.NewDomainPolicyChangedEvent(ctx, aggregate, changes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ func TestCommandSide_AddDomainPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -86,7 +86,7 @@ func TestCommandSide_AddDomainPolicy(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -194,7 +194,7 @@ func TestCommandSide_ChangeDomainPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -220,7 +220,7 @@ func TestCommandSide_ChangeDomainPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -229,7 +229,7 @@ func TestCommandSide_ChangeDomainPolicy(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
newOrgIAMPolicyChangedEvent(context.Background(), "org1", false),
|
newDomainPolicyChangedEvent(context.Background(), "org1", false),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -272,7 +272,7 @@ func TestCommandSide_ChangeDomainPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommandSide_RemoveOrgIAMPolicy(t *testing.T) {
|
func TestCommandSide_RemoveDomainPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ func TestCommandSide_RemoveOrgIAMPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -336,7 +336,7 @@ func TestCommandSide_RemoveOrgIAMPolicy(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyRemovedEvent(context.Background(),
|
org.NewDomainPolicyRemovedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate),
|
&org.NewAggregate("org1", "org1").Aggregate),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -370,8 +370,8 @@ func TestCommandSide_RemoveOrgIAMPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOrgIAMPolicyChangedEvent(ctx context.Context, orgID string, userLoginMustBeDomain bool) *org.OrgDomainPolicyChangedEvent {
|
func newDomainPolicyChangedEvent(ctx context.Context, orgID string, userLoginMustBeDomain bool) *org.DomainPolicyChangedEvent {
|
||||||
event, _ := org.NewOrgDomainPolicyChangedEvent(ctx,
|
event, _ := org.NewDomainPolicyChangedEvent(ctx,
|
||||||
&org.NewAggregate(orgID, orgID).Aggregate,
|
&org.NewAggregate(orgID, orgID).Aggregate,
|
||||||
[]policy.OrgPolicyChanges{
|
[]policy.OrgPolicyChanges{
|
||||||
policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain),
|
policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain),
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/repository/policy"
|
"github.com/caos/zitadel/internal/repository/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
hasStringLowerCase = regexp.MustCompile(`[a-z]`).MatchString
|
||||||
|
hasStringUpperCase = regexp.MustCompile(`[A-Z]`).MatchString
|
||||||
|
hasNumber = regexp.MustCompile(`[0-9]`).MatchString
|
||||||
|
hasSymbol = regexp.MustCompile(`[^A-Za-z0-9]`).MatchString
|
||||||
|
)
|
||||||
|
|
||||||
type PasswordComplexityPolicyWriteModel struct {
|
type PasswordComplexityPolicyWriteModel struct {
|
||||||
eventstore.WriteModel
|
eventstore.WriteModel
|
||||||
|
|
||||||
@ -49,3 +59,26 @@ func (wm *PasswordComplexityPolicyWriteModel) Reduce() error {
|
|||||||
}
|
}
|
||||||
return wm.WriteModel.Reduce()
|
return wm.WriteModel.Reduce()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wm *PasswordComplexityPolicyWriteModel) Validate(password string) error {
|
||||||
|
if wm.MinLength != 0 && uint64(len(password)) < wm.MinLength {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "COMMA-HuJf6", "Errors.User.PasswordComplexityPolicy.MinLength")
|
||||||
|
}
|
||||||
|
|
||||||
|
if wm.HasLowercase && !hasStringLowerCase(password) {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "COMMA-co3Xw", "Errors.User.PasswordComplexityPolicy.HasLower")
|
||||||
|
}
|
||||||
|
|
||||||
|
if wm.HasUppercase && !hasStringUpperCase(password) {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "COMMA-VoaRj", "Errors.User.PasswordComplexityPolicy.HasUpper")
|
||||||
|
}
|
||||||
|
|
||||||
|
if wm.HasNumber && !hasNumber(password) {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "COMMA-ZBv4H", "Errors.User.PasswordComplexityPolicy.HasNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
if wm.HasSymbol && !hasSymbol(password) {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "COMMA-ZDLwA", "Errors.User.PasswordComplexityPolicy.HasSymbol")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -1,329 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/crypto"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
|
||||||
iam_repo "github.com/caos/zitadel/internal/repository/instance"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
OIDCResponseTypeCode = "CODE"
|
|
||||||
OIDCResponseTypeIDToken = "ID_TOKEN"
|
|
||||||
OIDCResponseTypeToken = "ID_TOKEN TOKEN"
|
|
||||||
OIDCGrantTypeAuthorizationCode = "AUTHORIZATION_CODE"
|
|
||||||
OIDCGrantTypeImplicit = "IMPLICIT"
|
|
||||||
OIDCGrantTypeRefreshToken = "REFRESH_TOKEN"
|
|
||||||
OIDCApplicationTypeNative = "NATIVE"
|
|
||||||
OIDCApplicationTypeUserAgent = "USER_AGENT"
|
|
||||||
OIDCApplicationTypeWeb = "WEB"
|
|
||||||
AuthMethodTypeNone = "NONE"
|
|
||||||
AuthMethodTypeBasic = "BASIC"
|
|
||||||
AuthMethodTypePost = "POST"
|
|
||||||
AuthMethodTypePrivateKeyJWT = "PRIVATE_KEY_JWT"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step1 struct {
|
|
||||||
GlobalOrg string
|
|
||||||
IAMProject string
|
|
||||||
DefaultLoginPolicy LoginPolicy
|
|
||||||
Orgs []Org
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step1) Step() domain.Step {
|
|
||||||
return domain.Step1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step1) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep1(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginPolicy struct {
|
|
||||||
AllowRegister bool
|
|
||||||
AllowUsernamePassword bool
|
|
||||||
AllowExternalIdp bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
UserName string
|
|
||||||
Email string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Org struct {
|
|
||||||
Name string
|
|
||||||
Domain string
|
|
||||||
OrgIamPolicy bool
|
|
||||||
Owner User
|
|
||||||
Projects []Project
|
|
||||||
}
|
|
||||||
|
|
||||||
type Project struct {
|
|
||||||
Name string
|
|
||||||
Users []User
|
|
||||||
Members []string
|
|
||||||
OIDCApps []OIDCApp
|
|
||||||
APIs []API
|
|
||||||
}
|
|
||||||
|
|
||||||
type OIDCApp struct {
|
|
||||||
Name string
|
|
||||||
RedirectUris []string
|
|
||||||
ResponseTypes []string
|
|
||||||
GrantTypes []string
|
|
||||||
ApplicationType string
|
|
||||||
AuthMethodType string
|
|
||||||
PostLogoutRedirectUris []string
|
|
||||||
DevMode bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type API struct {
|
|
||||||
Name string
|
|
||||||
AuthMethodType string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep1(ctx context.Context, step1 *Step1) error {
|
|
||||||
var events []eventstore.Command
|
|
||||||
iamWriteModel := NewInstanceWriteModel()
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iamWriteModel.WriteModel)
|
|
||||||
//create default login policy
|
|
||||||
loginPolicyEvent, err := c.addDefaultLoginPolicy(ctx, iamAgg, NewInstanceLoginPolicyWriteModel(),
|
|
||||||
&domain.LoginPolicy{
|
|
||||||
AllowUsernamePassword: step1.DefaultLoginPolicy.AllowUsernamePassword,
|
|
||||||
AllowRegister: step1.DefaultLoginPolicy.AllowRegister,
|
|
||||||
AllowExternalIDP: step1.DefaultLoginPolicy.AllowExternalIdp,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, loginPolicyEvent)
|
|
||||||
logging.Log("SETUP-sd2hj").Info("default login policy set up")
|
|
||||||
//create orgs
|
|
||||||
for _, organisation := range step1.Orgs {
|
|
||||||
orgIAMPolicy := &domain.DomainPolicy{UserLoginMustBeDomain: true}
|
|
||||||
if organisation.OrgIamPolicy {
|
|
||||||
orgIAMPolicy.UserLoginMustBeDomain = false
|
|
||||||
}
|
|
||||||
pwPolicy := &domain.PasswordComplexityPolicy{
|
|
||||||
MinLength: 1,
|
|
||||||
}
|
|
||||||
orgAgg, _, humanWriteModel, _, setUpOrgEvents, err := c.setUpOrg(ctx,
|
|
||||||
&domain.Org{
|
|
||||||
Name: organisation.Name,
|
|
||||||
Domains: []*domain.OrgDomain{{Domain: organisation.Domain}},
|
|
||||||
},
|
|
||||||
&domain.Human{
|
|
||||||
Username: organisation.Owner.UserName,
|
|
||||||
Profile: &domain.Profile{
|
|
||||||
FirstName: organisation.Owner.FirstName,
|
|
||||||
LastName: organisation.Owner.LastName,
|
|
||||||
},
|
|
||||||
Password: &domain.Password{
|
|
||||||
SecretString: organisation.Owner.Password,
|
|
||||||
},
|
|
||||||
Email: &domain.Email{
|
|
||||||
EmailAddress: organisation.Owner.Email,
|
|
||||||
IsEmailVerified: true,
|
|
||||||
},
|
|
||||||
}, orgIAMPolicy, pwPolicy,
|
|
||||||
nil, //TODO: Code Generator missing! Should be setuped in step1 create iam
|
|
||||||
nil, //TODO: Code Generator missing! Should be setuped in step1 create iam
|
|
||||||
nil, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, setUpOrgEvents...)
|
|
||||||
logging.LogWithFields("SETUP-Gdsfg", "id", orgAgg.ID, "name", organisation.Name).Info("org set up")
|
|
||||||
|
|
||||||
if organisation.OrgIamPolicy {
|
|
||||||
orgIAMPolicyEvent, err := c.addOrgDomainPolicy(ctx, orgAgg, NewOrgDomainPolicyWriteModel(orgAgg.ID), orgIAMPolicy)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, orgIAMPolicyEvent)
|
|
||||||
}
|
|
||||||
if organisation.Name == step1.GlobalOrg {
|
|
||||||
globalOrgEvent, err := c.setGlobalOrg(ctx, iamAgg, iamWriteModel, orgAgg.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, globalOrgEvent)
|
|
||||||
logging.Log("SETUP-BDn52").Info("global org set")
|
|
||||||
}
|
|
||||||
//projects
|
|
||||||
for _, proj := range organisation.Projects {
|
|
||||||
project := &domain.Project{Name: proj.Name}
|
|
||||||
projectEvents, projectWriteModel, err := c.addProject(ctx, project, orgAgg.ID, humanWriteModel.AggregateID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, projectEvents...)
|
|
||||||
if project.Name == step1.IAMProject {
|
|
||||||
iamProjectEvent, err := c.setIAMProject(ctx, iamAgg, iamWriteModel, projectWriteModel.AggregateID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, iamProjectEvent)
|
|
||||||
logging.Log("SETUP-Bdfs1").Info("IAM project set")
|
|
||||||
iamEvent, err := c.addInstanceMember(ctx, iamAgg, NewInstanceMemberWriteModel(humanWriteModel.AggregateID), domain.NewMember(iamAgg.ID, humanWriteModel.AggregateID, domain.RoleIAMOwner))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, iamEvent)
|
|
||||||
logging.Log("SETUP-BSf2h").Info("IAM owner set")
|
|
||||||
}
|
|
||||||
//create applications
|
|
||||||
for _, app := range proj.OIDCApps {
|
|
||||||
//TODO: Add Secret Generator
|
|
||||||
applicationEvents, err := setUpOIDCApplication(ctx, c, projectWriteModel, project, app, orgAgg.ID, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, applicationEvents...)
|
|
||||||
}
|
|
||||||
for _, app := range proj.APIs {
|
|
||||||
//TODO: Add Secret Generator
|
|
||||||
applicationEvents, err := setUpAPI(ctx, c, projectWriteModel, project, app, orgAgg.ID, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events = append(events, applicationEvents...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
events = append(events, iam_repo.NewSetupStepDoneEvent(ctx, iamAgg, domain.Step1))
|
|
||||||
|
|
||||||
_, err = c.eventstore.Push(ctx, events...)
|
|
||||||
if err != nil {
|
|
||||||
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-Gr2hh", "Setup Step1 failed")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUpOIDCApplication(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteModel, project *domain.Project, oidcApp OIDCApp, resourceOwner string, appSecretGenerator crypto.Generator) ([]eventstore.Command, error) {
|
|
||||||
app := &domain.OIDCApp{
|
|
||||||
ObjectRoot: models.ObjectRoot{
|
|
||||||
AggregateID: projectWriteModel.AggregateID,
|
|
||||||
},
|
|
||||||
AppName: oidcApp.Name,
|
|
||||||
RedirectUris: oidcApp.RedirectUris,
|
|
||||||
ResponseTypes: getOIDCResponseTypes(oidcApp.ResponseTypes),
|
|
||||||
GrantTypes: getOIDCGrantTypes(oidcApp.GrantTypes),
|
|
||||||
ApplicationType: getOIDCApplicationType(oidcApp.ApplicationType),
|
|
||||||
AuthMethodType: getOIDCAuthMethod(oidcApp.AuthMethodType),
|
|
||||||
DevMode: oidcApp.DevMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel)
|
|
||||||
events, _, err := r.addOIDCApplication(ctx, projectAgg, project, app, resourceOwner, appSecretGenerator)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.LogWithFields("SETUP-Edgw4", "name", app.AppName, "clientID", app.ClientID).Info("application set up")
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUpAPI(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteModel, project *domain.Project, apiApp API, resourceOwner string, appSecretGenerator crypto.Generator) ([]eventstore.Command, error) {
|
|
||||||
app := &domain.APIApp{
|
|
||||||
ObjectRoot: models.ObjectRoot{
|
|
||||||
AggregateID: projectWriteModel.AggregateID,
|
|
||||||
},
|
|
||||||
AppName: apiApp.Name,
|
|
||||||
AuthMethodType: getAPIAuthMethod(apiApp.AuthMethodType),
|
|
||||||
}
|
|
||||||
|
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel)
|
|
||||||
events, _, err := r.addAPIApplication(ctx, projectAgg, project, app, resourceOwner, appSecretGenerator)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.LogWithFields("SETUP-Dbgsf", "name", app.AppName, "clientID", app.ClientID).Info("application set up")
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOIDCResponseTypes(responseTypes []string) []domain.OIDCResponseType {
|
|
||||||
types := make([]domain.OIDCResponseType, len(responseTypes))
|
|
||||||
for i, t := range responseTypes {
|
|
||||||
types[i] = getOIDCResponseType(t)
|
|
||||||
}
|
|
||||||
return types
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOIDCResponseType(responseType string) domain.OIDCResponseType {
|
|
||||||
switch responseType {
|
|
||||||
case OIDCResponseTypeCode:
|
|
||||||
return domain.OIDCResponseTypeCode
|
|
||||||
case OIDCResponseTypeIDToken:
|
|
||||||
return domain.OIDCResponseTypeIDToken
|
|
||||||
case OIDCResponseTypeToken:
|
|
||||||
return domain.OIDCResponseTypeIDTokenToken
|
|
||||||
}
|
|
||||||
return domain.OIDCResponseTypeCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOIDCGrantTypes(grantTypes []string) []domain.OIDCGrantType {
|
|
||||||
types := make([]domain.OIDCGrantType, len(grantTypes))
|
|
||||||
for i, t := range grantTypes {
|
|
||||||
types[i] = getOIDCGrantType(t)
|
|
||||||
}
|
|
||||||
return types
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOIDCGrantType(grantTypes string) domain.OIDCGrantType {
|
|
||||||
switch grantTypes {
|
|
||||||
case OIDCGrantTypeAuthorizationCode:
|
|
||||||
return domain.OIDCGrantTypeAuthorizationCode
|
|
||||||
case OIDCGrantTypeImplicit:
|
|
||||||
return domain.OIDCGrantTypeImplicit
|
|
||||||
case OIDCGrantTypeRefreshToken:
|
|
||||||
return domain.OIDCGrantTypeRefreshToken
|
|
||||||
}
|
|
||||||
return domain.OIDCGrantTypeAuthorizationCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOIDCApplicationType(appType string) domain.OIDCApplicationType {
|
|
||||||
switch appType {
|
|
||||||
case OIDCApplicationTypeNative:
|
|
||||||
return domain.OIDCApplicationTypeNative
|
|
||||||
case OIDCApplicationTypeUserAgent:
|
|
||||||
return domain.OIDCApplicationTypeUserAgent
|
|
||||||
case OIDCApplicationTypeWeb:
|
|
||||||
return domain.OIDCApplicationTypeWeb
|
|
||||||
}
|
|
||||||
return domain.OIDCApplicationTypeWeb
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOIDCAuthMethod(authMethod string) domain.OIDCAuthMethodType {
|
|
||||||
switch authMethod {
|
|
||||||
case AuthMethodTypeNone:
|
|
||||||
return domain.OIDCAuthMethodTypeNone
|
|
||||||
case AuthMethodTypeBasic:
|
|
||||||
return domain.OIDCAuthMethodTypeBasic
|
|
||||||
case AuthMethodTypePost:
|
|
||||||
return domain.OIDCAuthMethodTypePost
|
|
||||||
case AuthMethodTypePrivateKeyJWT:
|
|
||||||
return domain.OIDCAuthMethodTypePrivateKeyJWT
|
|
||||||
}
|
|
||||||
return domain.OIDCAuthMethodTypeBasic
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAPIAuthMethod(authMethod string) domain.APIAuthMethodType {
|
|
||||||
switch authMethod {
|
|
||||||
case AuthMethodTypeBasic:
|
|
||||||
return domain.APIAuthMethodTypeBasic
|
|
||||||
case AuthMethodTypePrivateKeyJWT:
|
|
||||||
return domain.APIAuthMethodTypePrivateKeyJWT
|
|
||||||
}
|
|
||||||
return domain.APIAuthMethodTypePrivateKeyJWT
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step10 struct {
|
|
||||||
DefaultMailTemplate domain.MailTemplate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step10) Step() domain.Step {
|
|
||||||
return domain.Step10
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step10) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep10(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep10(ctx context.Context, step *Step10) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
mailTemplateEvent, err := c.addDefaultMailTemplate(ctx, iamAgg, NewInstanceMailTemplateWriteModel(), &step.DefaultMailTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
events := []eventstore.Command{
|
|
||||||
mailTemplateEvent,
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-3N9fs").Info("default mail template/text set up")
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
iam_repo "github.com/caos/zitadel/internal/repository/instance"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step11 struct {
|
|
||||||
MigrateV1EventstoreToV2 bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step11) Step() domain.Step {
|
|
||||||
return domain.Step11
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step11) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep11(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep11(ctx context.Context, step *Step11) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
var uniqueContraintMigrations []*domain.UniqueConstraintMigration
|
|
||||||
if step.MigrateV1EventstoreToV2 {
|
|
||||||
uniqueConstraints := NewUniqueConstraintReadModel(ctx, c)
|
|
||||||
err := c.eventstore.FilterToQueryReducer(ctx, uniqueConstraints)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
uniqueContraintMigrations = uniqueConstraints.UniqueConstraints
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-M9fsd").Info("migrate v1 eventstore to v2")
|
|
||||||
return []eventstore.Command{iam_repo.NewMigrateUniqueConstraintEvent(ctx, iamAgg, uniqueContraintMigrations)}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step12 struct {
|
|
||||||
TierName string
|
|
||||||
TierDescription string
|
|
||||||
AuditLogRetention time.Duration
|
|
||||||
LoginPolicyFactors bool
|
|
||||||
LoginPolicyIDP bool
|
|
||||||
LoginPolicyPasswordless bool
|
|
||||||
LoginPolicyRegistration bool
|
|
||||||
LoginPolicyUsernameLogin bool
|
|
||||||
PasswordComplexityPolicy bool
|
|
||||||
LabelPolicy bool
|
|
||||||
CustomDomain bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step12) Step() domain.Step {
|
|
||||||
return domain.Step12
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step12) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep12(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep12(ctx context.Context, step *Step12) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
featuresWriteModel := NewInstanceFeaturesWriteModel()
|
|
||||||
featuresEvent, err := c.setDefaultFeatures(ctx, featuresWriteModel, &domain.Features{
|
|
||||||
TierName: step.TierName,
|
|
||||||
TierDescription: step.TierDescription,
|
|
||||||
State: domain.FeaturesStateActive,
|
|
||||||
AuditLogRetention: step.AuditLogRetention,
|
|
||||||
LoginPolicyFactors: step.LoginPolicyFactors,
|
|
||||||
LoginPolicyIDP: step.LoginPolicyIDP,
|
|
||||||
LoginPolicyPasswordless: step.LoginPolicyPasswordless,
|
|
||||||
LoginPolicyRegistration: step.LoginPolicyRegistration,
|
|
||||||
LoginPolicyUsernameLogin: step.LoginPolicyUsernameLogin,
|
|
||||||
PasswordComplexityPolicy: step.PasswordComplexityPolicy,
|
|
||||||
LabelPolicyPrivateLabel: step.LabelPolicy,
|
|
||||||
CustomDomain: step.CustomDomain,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return []eventstore.Command{featuresEvent}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step13 struct {
|
|
||||||
DefaultMailTemplate domain.MailTemplate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step13) Step() domain.Step {
|
|
||||||
return domain.Step13
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step13) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep13(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep13(ctx context.Context, step *Step13) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
_, mailTemplateEvent, err := c.changeDefaultMailTemplate(ctx, &step.DefaultMailTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-4insR").Info("default mail template/text set up")
|
|
||||||
return []eventstore.Command{mailTemplateEvent}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
iam_repo "github.com/caos/zitadel/internal/repository/instance"
|
|
||||||
org_repo "github.com/caos/zitadel/internal/repository/org"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step14 struct {
|
|
||||||
ActivateExistingLabelPolicies bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step14) Step() domain.Step {
|
|
||||||
return domain.Step14
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step14) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep14(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep14(ctx context.Context, step *Step14) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
var events []eventstore.Command
|
|
||||||
if step.ActivateExistingLabelPolicies {
|
|
||||||
existingPolicies := NewExistingLabelPoliciesReadModel(ctx)
|
|
||||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicies)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, aggID := range existingPolicies.aggregateIDs {
|
|
||||||
if iamAgg.ID == aggID {
|
|
||||||
events = append(events, iam_repo.NewLabelPolicyActivatedEvent(ctx, iamAgg))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
events = append(events, org_repo.NewLabelPolicyActivatedEvent(ctx, &org_repo.NewAggregate(aggID, aggID).Aggregate))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-M9fsd").Info("activate login policies")
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step15 struct {
|
|
||||||
DefaultMailTemplate domain.MailTemplate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step15) Step() domain.Step {
|
|
||||||
return domain.Step15
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step15) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep15(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep15(ctx context.Context, step *Step15) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
_, mailTemplateEvent, err := c.changeDefaultMailTemplate(ctx, &step.DefaultMailTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-2nfsd").Info("default mail template/text set up")
|
|
||||||
return []eventstore.Command{mailTemplateEvent}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step16 struct {
|
|
||||||
DefaultMessageTexts []domain.CustomMessageText
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step16) Step() domain.Step {
|
|
||||||
return domain.Step16
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step16) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep16(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep16(ctx context.Context, step *Step16) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
events := make([]eventstore.Command, 0)
|
|
||||||
|
|
||||||
for _, text := range step.DefaultMessageTexts {
|
|
||||||
mailEvents, _, err := c.setDefaultMessageText(ctx, iamAgg, &text)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
events = append(events, mailEvents...)
|
|
||||||
}
|
|
||||||
|
|
||||||
logging.Log("SETUP-4k0LL").Info("default message text set up")
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step17 struct {
|
|
||||||
PrivacyPolicy domain.PrivacyPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step17) Step() domain.Step {
|
|
||||||
return domain.Step17
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step17) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep17(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep17(ctx context.Context, step *Step17) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
addedPolicy := NewInstancePrivacyPolicyWriteModel()
|
|
||||||
events, err := c.addDefaultPrivacyPolicy(ctx, iamAgg, addedPolicy, &step.PrivacyPolicy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logging.Log("SETUP-N9sq2").Info("default privacy policy set up")
|
|
||||||
return []eventstore.Command{events}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step18 struct {
|
|
||||||
LockoutPolicy domain.LockoutPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step18) Step() domain.Step {
|
|
||||||
return domain.Step18
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step18) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep18(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep18(ctx context.Context, step *Step18) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
addedPolicy := NewInstanceLockoutPolicyWriteModel()
|
|
||||||
events, err := c.addDefaultLockoutPolicy(ctx, iamAgg, addedPolicy, &step.LockoutPolicy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logging.Log("SETUP-3m99ds").Info("default lockout policy set up")
|
|
||||||
return []eventstore.Command{events}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,212 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
"github.com/caos/zitadel/internal/repository/org"
|
|
||||||
"github.com/caos/zitadel/internal/repository/user"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step19 struct{}
|
|
||||||
|
|
||||||
func (s *Step19) Step() domain.Step {
|
|
||||||
return domain.Step19
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step19) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep19(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep19(ctx context.Context, step *Step19) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
events := make([]eventstore.Command, 0)
|
|
||||||
orgs := newOrgsWithUsernameNotDomain()
|
|
||||||
if err := c.eventstore.FilterToQueryReducer(ctx, orgs); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for orgID, usernameCheck := range orgs.orgs {
|
|
||||||
if !usernameCheck {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
users := newDomainClaimedUsernames(orgID)
|
|
||||||
if err := c.eventstore.FilterToQueryReducer(ctx, users); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for userID, username := range users.users {
|
|
||||||
split := strings.Split(username, "@")
|
|
||||||
if len(split) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
domainVerified := NewOrgDomainVerifiedWriteModel(split[1])
|
|
||||||
if err := c.eventstore.FilterToQueryReducer(ctx, domainVerified); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if domainVerified.Verified && domainVerified.ResourceOwner != orgID {
|
|
||||||
id, err := c.idGenerator.Next()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
events = append(events, user.NewDomainClaimedEvent(
|
|
||||||
ctx,
|
|
||||||
&user.NewAggregate(userID, orgID).Aggregate,
|
|
||||||
fmt.Sprintf("%s@temporary.%s", id, c.iamDomain),
|
|
||||||
username,
|
|
||||||
false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if length := len(events); length > 0 {
|
|
||||||
logging.Log("SETUP-dFG2t").WithField("count", length).Info("domain claimed events created")
|
|
||||||
}
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOrgsWithUsernameNotDomain() *orgsWithUsernameNotDomain {
|
|
||||||
return &orgsWithUsernameNotDomain{
|
|
||||||
orgEvents: make(map[string][]eventstore.Event),
|
|
||||||
orgs: make(map[string]bool),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type orgsWithUsernameNotDomain struct {
|
|
||||||
eventstore.WriteModel
|
|
||||||
|
|
||||||
orgEvents map[string][]eventstore.Event
|
|
||||||
orgs map[string]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *orgsWithUsernameNotDomain) AppendEvents(events ...eventstore.Event) {
|
|
||||||
for _, event := range events {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *org.OrgAddedEvent:
|
|
||||||
wm.orgEvents[e.Aggregate().ID] = append(wm.orgEvents[e.Aggregate().ID], e)
|
|
||||||
case *org.OrgRemovedEvent:
|
|
||||||
delete(wm.orgEvents, e.Aggregate().ID)
|
|
||||||
case *org.OrgDomainPolicyAddedEvent:
|
|
||||||
wm.orgEvents[e.Aggregate().ID] = append(wm.orgEvents[e.Aggregate().ID], e)
|
|
||||||
case *org.OrgDomainPolicyChangedEvent:
|
|
||||||
if e.UserLoginMustBeDomain == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
wm.orgEvents[e.Aggregate().ID] = append(wm.orgEvents[e.Aggregate().ID], e)
|
|
||||||
case *org.OrgDomainPolicyRemovedEvent:
|
|
||||||
delete(wm.orgEvents, e.Aggregate().ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *orgsWithUsernameNotDomain) Reduce() error {
|
|
||||||
for _, events := range wm.orgEvents {
|
|
||||||
for _, event := range events {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *org.OrgDomainPolicyAddedEvent:
|
|
||||||
if !e.UserLoginMustBeDomain {
|
|
||||||
wm.orgs[e.Aggregate().ID] = true
|
|
||||||
}
|
|
||||||
case *org.OrgDomainPolicyChangedEvent:
|
|
||||||
if !*e.UserLoginMustBeDomain {
|
|
||||||
wm.orgs[e.Aggregate().ID] = true
|
|
||||||
}
|
|
||||||
delete(wm.orgs, e.Aggregate().ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *orgsWithUsernameNotDomain) Query() *eventstore.SearchQueryBuilder {
|
|
||||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
|
||||||
AddQuery().
|
|
||||||
AggregateTypes(org.AggregateType).
|
|
||||||
EventTypes(
|
|
||||||
org.OrgAddedEventType,
|
|
||||||
org.OrgRemovedEventType,
|
|
||||||
org.OrgDomainPolicyAddedEventType,
|
|
||||||
org.OrgDomainPolicyChangedEventType,
|
|
||||||
org.OrgDomainPolicyRemovedEventType).
|
|
||||||
Builder()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDomainClaimedUsernames(orgID string) *domainClaimedUsernames {
|
|
||||||
return &domainClaimedUsernames{
|
|
||||||
WriteModel: eventstore.WriteModel{
|
|
||||||
ResourceOwner: orgID,
|
|
||||||
},
|
|
||||||
userEvents: make(map[string][]eventstore.Event),
|
|
||||||
users: make(map[string]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type domainClaimedUsernames struct {
|
|
||||||
eventstore.WriteModel
|
|
||||||
|
|
||||||
userEvents map[string][]eventstore.Event
|
|
||||||
users map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *domainClaimedUsernames) AppendEvents(events ...eventstore.Event) {
|
|
||||||
for _, event := range events {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *user.HumanAddedEvent:
|
|
||||||
if !strings.Contains(e.UserName, "@") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
wm.userEvents[e.Aggregate().ID] = append(wm.userEvents[e.Aggregate().ID], e)
|
|
||||||
case *user.HumanRegisteredEvent:
|
|
||||||
if !strings.Contains(e.UserName, "@") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
wm.userEvents[e.Aggregate().ID] = append(wm.userEvents[e.Aggregate().ID], e)
|
|
||||||
case *user.UsernameChangedEvent:
|
|
||||||
if !strings.Contains(e.UserName, "@") {
|
|
||||||
delete(wm.userEvents, e.Aggregate().ID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
wm.userEvents[e.Aggregate().ID] = append(wm.userEvents[e.Aggregate().ID], e)
|
|
||||||
case *user.DomainClaimedEvent:
|
|
||||||
delete(wm.userEvents, e.Aggregate().ID)
|
|
||||||
case *user.UserRemovedEvent:
|
|
||||||
delete(wm.userEvents, e.Aggregate().ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *domainClaimedUsernames) Reduce() error {
|
|
||||||
for _, events := range wm.userEvents {
|
|
||||||
for _, event := range events {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *user.HumanAddedEvent:
|
|
||||||
wm.users[e.Aggregate().ID] = e.UserName
|
|
||||||
case *user.HumanRegisteredEvent:
|
|
||||||
wm.users[e.Aggregate().ID] = e.UserName
|
|
||||||
case *user.UsernameChangedEvent:
|
|
||||||
wm.users[e.Aggregate().ID] = e.UserName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *domainClaimedUsernames) Query() *eventstore.SearchQueryBuilder {
|
|
||||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
|
||||||
ResourceOwner(wm.ResourceOwner).
|
|
||||||
AddQuery().
|
|
||||||
AggregateTypes(user.AggregateType).
|
|
||||||
EventTypes(
|
|
||||||
user.UserV1AddedType,
|
|
||||||
user.UserV1RegisteredType,
|
|
||||||
user.HumanAddedType,
|
|
||||||
user.HumanRegisteredType,
|
|
||||||
user.UserUserNameChangedType,
|
|
||||||
user.UserDomainClaimedType,
|
|
||||||
user.UserRemovedType).
|
|
||||||
Builder()
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step2 struct {
|
|
||||||
DefaultPasswordComplexityPolicy domain.PasswordComplexityPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step2) Step() domain.Step {
|
|
||||||
return domain.Step2
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step2) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep2(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep2(ctx context.Context, step *Step2) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
event, err := c.addDefaultPasswordComplexityPolicy(ctx, iamAgg, NewInstancePasswordComplexityPolicyWriteModel(), &domain.PasswordComplexityPolicy{
|
|
||||||
MinLength: step.DefaultPasswordComplexityPolicy.MinLength,
|
|
||||||
HasLowercase: step.DefaultPasswordComplexityPolicy.HasLowercase,
|
|
||||||
HasUppercase: step.DefaultPasswordComplexityPolicy.HasUppercase,
|
|
||||||
HasNumber: step.DefaultPasswordComplexityPolicy.HasNumber,
|
|
||||||
HasSymbol: step.DefaultPasswordComplexityPolicy.HasSymbol,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-ADgd2").Info("default password complexity policy set up")
|
|
||||||
return []eventstore.Command{event}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step20 struct{}
|
|
||||||
|
|
||||||
func (s *Step20) Step() domain.Step {
|
|
||||||
return domain.Step20
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step20) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep20(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep20(ctx context.Context, step *Step20) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
err := c.eventstore.Step20(ctx, iam.Events[len(iam.Events)-1].Sequence())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
"github.com/caos/zitadel/internal/repository/org"
|
|
||||||
"github.com/caos/zitadel/internal/repository/user"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step21 struct{}
|
|
||||||
|
|
||||||
func (s *Step21) Step() domain.Step {
|
|
||||||
return domain.Step21
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step21) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep21(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep21(ctx context.Context, step *Step21) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
events := make([]eventstore.Command, 0)
|
|
||||||
globalMembers := newGlobalOrgMemberWriteModel(iam.GlobalOrgID, domain.RoleOrgProjectCreator)
|
|
||||||
orgAgg := OrgAggregateFromWriteModel(&globalMembers.WriteModel)
|
|
||||||
if err := c.eventstore.FilterToQueryReducer(ctx, globalMembers); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for userID, roles := range globalMembers.members {
|
|
||||||
for i, role := range roles {
|
|
||||||
if role == domain.RoleOrgProjectCreator {
|
|
||||||
roles[i] = domain.RoleSelfManagementGlobal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
events = append(events, org.NewMemberChangedEvent(ctx, orgAgg, userID, roles...))
|
|
||||||
}
|
|
||||||
return events, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
type globalOrgMembersWriteModel struct {
|
|
||||||
eventstore.WriteModel
|
|
||||||
|
|
||||||
role string
|
|
||||||
members map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGlobalOrgMemberWriteModel(orgID, role string) *globalOrgMembersWriteModel {
|
|
||||||
return &globalOrgMembersWriteModel{
|
|
||||||
WriteModel: eventstore.WriteModel{
|
|
||||||
ResourceOwner: orgID,
|
|
||||||
AggregateID: orgID,
|
|
||||||
},
|
|
||||||
role: role,
|
|
||||||
members: make(map[string][]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *globalOrgMembersWriteModel) Reduce() error {
|
|
||||||
for _, event := range wm.Events {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *org.MemberAddedEvent:
|
|
||||||
for _, role := range e.Roles {
|
|
||||||
if wm.role == role {
|
|
||||||
wm.members[e.UserID] = e.Roles
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *org.MemberChangedEvent:
|
|
||||||
delete(wm.members, e.UserID)
|
|
||||||
for _, role := range e.Roles {
|
|
||||||
if wm.role == role {
|
|
||||||
wm.members[e.UserID] = e.Roles
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *org.MemberRemovedEvent:
|
|
||||||
delete(wm.members, e.UserID)
|
|
||||||
case *org.MemberCascadeRemovedEvent:
|
|
||||||
delete(wm.members, e.UserID)
|
|
||||||
case *user.UserRemovedEvent:
|
|
||||||
delete(wm.members, e.Aggregate().ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wm.WriteModel.Reduce()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wm *globalOrgMembersWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|
||||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
|
||||||
AddQuery().
|
|
||||||
AggregateTypes(org.AggregateType).
|
|
||||||
AggregateIDs(wm.AggregateID).
|
|
||||||
EventTypes(
|
|
||||||
org.MemberAddedEventType,
|
|
||||||
org.MemberChangedEventType,
|
|
||||||
org.MemberRemovedEventType,
|
|
||||||
org.MemberCascadeRemovedEventType,
|
|
||||||
).
|
|
||||||
Or().
|
|
||||||
AggregateTypes(user.AggregateType).
|
|
||||||
EventTypes(user.UserRemovedType).
|
|
||||||
Builder()
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step3 struct {
|
|
||||||
DefaultPasswordAgePolicy domain.PasswordAgePolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step3) Step() domain.Step {
|
|
||||||
return domain.Step3
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step3) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep3(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep3(ctx context.Context, step *Step3) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
event, err := c.addDefaultPasswordAgePolicy(ctx, iamAgg, NewInstancePasswordAgePolicyWriteModel(), &domain.PasswordAgePolicy{
|
|
||||||
MaxAgeDays: step.DefaultPasswordAgePolicy.MaxAgeDays,
|
|
||||||
ExpireWarnDays: step.DefaultPasswordAgePolicy.ExpireWarnDays,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-DBqgq").Info("default password age policy set up")
|
|
||||||
return []eventstore.Command{event}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step4 struct {
|
|
||||||
DefaultPasswordLockoutPolicy domain.LockoutPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step4) Step() domain.Step {
|
|
||||||
return domain.Step4
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step4) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep4(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
//This step should not be executed when a new instance is setup, because its not used anymore
|
|
||||||
//SetupStep4 is no op in favour of step 18.
|
|
||||||
//Password lockout policy is replaced by lockout policy
|
|
||||||
func (c *Commands) SetupStep4(ctx context.Context, step *Step4) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step5 struct {
|
|
||||||
DefaultOrgIAMPolicy domain.DomainPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step5) Step() domain.Step {
|
|
||||||
return domain.Step5
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step5) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep5(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep5(ctx context.Context, step *Step5) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
event, err := c.addDefaultDomainPolicy(ctx, iamAgg, NewInstanceDomainPolicyWriteModel(), &domain.DomainPolicy{
|
|
||||||
UserLoginMustBeDomain: step.DefaultOrgIAMPolicy.UserLoginMustBeDomain,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-ADgd2").Info("default org iam policy set up")
|
|
||||||
return []eventstore.Command{event}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step6 struct {
|
|
||||||
DefaultLabelPolicy domain.LabelPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step6) Step() domain.Step {
|
|
||||||
return domain.Step6
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step6) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep6(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep6(ctx context.Context, step *Step6) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&iam.WriteModel)
|
|
||||||
event, err := c.addDefaultLabelPolicy(ctx, iamAgg, NewInstanceLabelPolicyWriteModel(), &step.DefaultLabelPolicy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-ADgd2").Info("default label policy set up")
|
|
||||||
return []eventstore.Command{event}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step7 struct {
|
|
||||||
OTP bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step7) Step() domain.Step {
|
|
||||||
return domain.Step7
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step7) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep7(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep7(ctx context.Context, step *Step7) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
secondFactorModel := NewInstanceSecondFactorWriteModel(domain.SecondFactorTypeOTP)
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
|
|
||||||
if !step.OTP {
|
|
||||||
return []eventstore.Command{}, nil
|
|
||||||
}
|
|
||||||
event, err := c.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeOTP)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-Dggsg").Info("added OTP to 2FA login policy")
|
|
||||||
return []eventstore.Command{event}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step8 struct {
|
|
||||||
U2F bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step8) Step() domain.Step {
|
|
||||||
return domain.Step8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step8) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep8(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep8(ctx context.Context, step *Step8) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
secondFactorModel := NewInstanceSecondFactorWriteModel(domain.SecondFactorTypeU2F)
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
|
|
||||||
if !step.U2F {
|
|
||||||
return []eventstore.Command{}, nil
|
|
||||||
}
|
|
||||||
event, err := c.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeU2F)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-BDhne").Info("added U2F to 2FA login policy")
|
|
||||||
return []eventstore.Command{event}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step9 struct {
|
|
||||||
Passwordless bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step9) Step() domain.Step {
|
|
||||||
return domain.Step9
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step9) execute(ctx context.Context, commandSide *Commands) error {
|
|
||||||
return commandSide.SetupStep9(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) SetupStep9(ctx context.Context, step *Step9) error {
|
|
||||||
fn := func(iam *InstanceWriteModel) ([]eventstore.Command, error) {
|
|
||||||
multiFactorModel := NewInstanceMultiFactorWriteModel(domain.MultiFactorTypeU2FWithPIN)
|
|
||||||
iamAgg := InstanceAggregateFromWriteModel(&multiFactorModel.MultiFactorWriteModel.WriteModel)
|
|
||||||
if !step.Passwordless {
|
|
||||||
return []eventstore.Command{}, nil
|
|
||||||
}
|
|
||||||
passwordlessEvent, err := setPasswordlessAllowedInPolicy(ctx, c, iamAgg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-AEG2t").Info("allowed passwordless in login policy")
|
|
||||||
multifactorEvent, err := c.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, domain.MultiFactorTypeU2FWithPIN)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logging.Log("SETUP-ADfng").Info("added passwordless to MFA login policy")
|
|
||||||
return []eventstore.Command{passwordlessEvent, multifactorEvent}, nil
|
|
||||||
}
|
|
||||||
return c.setup(ctx, step, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setPasswordlessAllowedInPolicy(ctx context.Context, c *Commands, iamAgg *eventstore.Aggregate) (eventstore.Command, error) {
|
|
||||||
policy, err := c.getDefaultLoginPolicy(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
policy.PasswordlessType = domain.PasswordlessTypeAllowed
|
|
||||||
return c.changeDefaultLoginPolicy(ctx, iamAgg, NewInstanceLoginPolicyWriteModel(), policy)
|
|
||||||
}
|
|
@ -36,18 +36,18 @@ func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName s
|
|||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6m9gs", "Errors.User.UsernameNotChanged")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6m9gs", "Errors.User.UsernameNotChanged")
|
||||||
}
|
}
|
||||||
|
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.DomainPolicy.NotExisting")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.DomainPolicy.NotExisting")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := CheckDomainPolicyForUserName(userName, orgIAMPolicy); err != nil {
|
if err := CheckDomainPolicyForUserName(userName, domainPolicy); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||||
|
|
||||||
pushedEvents, err := c.eventstore.Push(ctx,
|
pushedEvents, err := c.eventstore.Push(ctx,
|
||||||
user.NewUsernameChangedEvent(ctx, userAgg, existingUser.UserName, userName, orgIAMPolicy.UserLoginMustBeDomain))
|
user.NewUsernameChangedEvent(ctx, userAgg, existingUser.UserName, userName, domainPolicy.UserLoginMustBeDomain))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -186,13 +186,13 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
|
|||||||
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-m9od", "Errors.User.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-m9od", "Errors.User.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, existingUser.ResourceOwner)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, existingUser.ResourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.OrgIAMPolicy.NotExisting")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.DomainPolicy.NotExisting")
|
||||||
}
|
}
|
||||||
var events []eventstore.Command
|
var events []eventstore.Command
|
||||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||||
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, existingUser.IDPLinks, orgIAMPolicy.UserLoginMustBeDomain))
|
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, existingUser.IDPLinks, domainPolicy.UserLoginMustBeDomain))
|
||||||
|
|
||||||
for _, grantID := range cascadingGrantIDs {
|
for _, grantID := range cascadingGrantIDs {
|
||||||
removeEvent, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
removeEvent, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
||||||
@ -320,7 +320,7 @@ func (c *Commands) userDomainClaimed(ctx context.Context, userID string) (events
|
|||||||
changedUserGrant := NewUserWriteModel(userID, existingUser.ResourceOwner)
|
changedUserGrant := NewUserWriteModel(userID, existingUser.ResourceOwner)
|
||||||
userAgg := UserAggregateFromWriteModel(&changedUserGrant.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&changedUserGrant.WriteModel)
|
||||||
|
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, existingUser.ResourceOwner)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, existingUser.ResourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -335,7 +335,7 @@ func (c *Commands) userDomainClaimed(ctx context.Context, userID string) (events
|
|||||||
userAgg,
|
userAgg,
|
||||||
fmt.Sprintf("%s@temporary.%s", id, c.iamDomain),
|
fmt.Sprintf("%s@temporary.%s", id, c.iamDomain),
|
||||||
existingUser.UserName,
|
existingUser.UserName,
|
||||||
orgIAMPolicy.UserLoginMustBeDomain),
|
domainPolicy.UserLoginMustBeDomain),
|
||||||
}, changedUserGrant, nil
|
}, changedUserGrant, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Hum
|
|||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-XYFk9", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-XYFk9", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.Org.DomainPolicy.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.Org.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Hum
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexityPolicy.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexityPolicy.NotFound")
|
||||||
}
|
}
|
||||||
events, addedHuman, err := c.addHuman(ctx, orgID, human, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
events, addedHuman, err := c.addHuman(ctx, orgID, human, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5N8fs", "Errors.ResourceOwnerMissing")
|
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5N8fs", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-2N9fs", "Errors.Org.DomainPolicy.NotFound")
|
return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-2N9fs", "Errors.Org.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexityPolicy.NotFound")
|
return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexityPolicy.NotFound")
|
||||||
}
|
}
|
||||||
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -89,21 +89,21 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
return writeModelToHuman(addedHuman), passwordlessCode, nil
|
return writeModelToHuman(addedHuman), passwordlessCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, orgIAMPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||||
if orgID == "" || !human.IsValid() {
|
if orgID == "" || !human.IsValid() {
|
||||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-67Ms8", "Errors.User.Invalid")
|
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-67Ms8", "Errors.User.Invalid")
|
||||||
}
|
}
|
||||||
if human.Password != nil && human.SecretString != "" {
|
if human.Password != nil && human.SecretString != "" {
|
||||||
human.ChangeRequired = true
|
human.ChangeRequired = true
|
||||||
}
|
}
|
||||||
return c.createHuman(ctx, orgID, human, nil, false, false, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
return c.createHuman(ctx, orgID, human, nil, false, false, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, orgIAMPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
||||||
if orgID == "" || !human.IsValid() {
|
if orgID == "" || !human.IsValid() {
|
||||||
return nil, nil, nil, "", caos_errs.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
|
return nil, nil, nil, "", caos_errs.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
|
||||||
}
|
}
|
||||||
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, "", err
|
return nil, nil, nil, "", err
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
|||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.Org.DomainPolicy.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.Org.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
|||||||
if !loginPolicy.AllowRegister {
|
if !loginPolicy.AllowRegister {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-SAbr3", "Errors.Org.LoginPolicy.RegistrationNotAllowed")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-SAbr3", "Errors.Org.LoginPolicy.RegistrationNotAllowed")
|
||||||
}
|
}
|
||||||
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
|||||||
return writeModelToHuman(registeredHuman), nil
|
return writeModelToHuman(registeredHuman), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgIAMPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||||
if human != nil && human.Username == "" {
|
if human != nil && human.Username == "" {
|
||||||
human.Username = human.EmailAddress
|
human.Username = human.EmailAddress
|
||||||
}
|
}
|
||||||
@ -181,14 +181,14 @@ func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domai
|
|||||||
if human.Password != nil && human.SecretString != "" {
|
if human.Password != nil && human.SecretString != "" {
|
||||||
human.ChangeRequired = false
|
human.ChangeRequired = false
|
||||||
}
|
}
|
||||||
return c.createHuman(ctx, orgID, human, link, true, false, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
return c.createHuman(ctx, orgID, human, link, true, false, domainPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, orgIAMPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
|
||||||
if err := human.CheckDomainPolicy(orgIAMPolicy); err != nil {
|
if err := human.CheckDomainPolicy(domainPolicy); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if !orgIAMPolicy.UserLoginMustBeDomain {
|
if !domainPolicy.UserLoginMustBeDomain {
|
||||||
usernameSplit := strings.Split(human.Username, "@")
|
usernameSplit := strings.Split(human.Username, "@")
|
||||||
if len(usernameSplit) != 2 {
|
if len(usernameSplit) != 2 {
|
||||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Dfd21", "Errors.User.Invalid")
|
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Dfd21", "Errors.User.Invalid")
|
||||||
@ -219,9 +219,9 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
var events []eventstore.Command
|
var events []eventstore.Command
|
||||||
|
|
||||||
if selfregister {
|
if selfregister {
|
||||||
events = append(events, createRegisterHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
|
events = append(events, createRegisterHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
|
||||||
} else {
|
} else {
|
||||||
events = append(events, createAddHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
|
events = append(events, createAddHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
|
||||||
}
|
}
|
||||||
|
|
||||||
if link != nil {
|
if link != nil {
|
||||||
|
@ -67,7 +67,8 @@ func (wm *HumanInitCodeWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
AddQuery().
|
AddQuery().
|
||||||
AggregateTypes(user.AggregateType).
|
AggregateTypes(user.AggregateType).
|
||||||
AggregateIDs(wm.AggregateID).
|
AggregateIDs(wm.AggregateID).
|
||||||
EventTypes(user.UserV1AddedType,
|
EventTypes(
|
||||||
|
user.UserV1AddedType,
|
||||||
user.HumanAddedType,
|
user.HumanAddedType,
|
||||||
user.UserV1RegisteredType,
|
user.UserV1RegisteredType,
|
||||||
user.HumanRegisteredType,
|
user.HumanRegisteredType,
|
||||||
|
@ -109,7 +109,8 @@ func (wm *HumanWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
AddQuery().
|
AddQuery().
|
||||||
AggregateTypes(user.AggregateType).
|
AggregateTypes(user.AggregateType).
|
||||||
AggregateIDs(wm.AggregateID).
|
AggregateIDs(wm.AggregateID).
|
||||||
EventTypes(user.HumanAddedType,
|
EventTypes(
|
||||||
|
user.HumanAddedType,
|
||||||
user.HumanRegisteredType,
|
user.HumanRegisteredType,
|
||||||
user.HumanInitialCodeAddedType,
|
user.HumanInitialCodeAddedType,
|
||||||
user.HumanInitializedCheckSucceededType,
|
user.HumanInitializedCheckSucceededType,
|
||||||
|
@ -28,7 +28,7 @@ func (c *Commands) AddHumanOTP(ctx context.Context, userID, resourceowner string
|
|||||||
orgPolicy, err := c.getOrgDomainPolicy(ctx, org.AggregateID)
|
orgPolicy, err := c.getOrgDomainPolicy(ctx, org.AggregateID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log("COMMAND-y5zv9").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get org policy for loginname")
|
logging.Log("COMMAND-y5zv9").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get org policy for loginname")
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-8ugTs", "Errors.Org.OrgIAMPolicy.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-8ugTs", "Errors.Org.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
otpWriteModel, err := c.otpWriteModelByID(ctx, userID, resourceowner)
|
otpWriteModel, err := c.otpWriteModelByID(ctx, userID, resourceowner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -176,7 +176,7 @@ func TestCommandSide_AddHumanOTP(t *testing.T) {
|
|||||||
),
|
),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
@ -102,7 +102,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -137,7 +137,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -178,7 +178,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -272,7 +272,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -359,7 +359,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -440,7 +440,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -539,7 +539,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -732,7 +732,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -767,7 +767,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -808,7 +808,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -896,7 +896,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -978,7 +978,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1082,7 +1082,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1190,7 +1190,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1294,7 +1294,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1495,7 +1495,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1533,7 +1533,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1579,7 +1579,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1641,7 +1641,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1703,7 +1703,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
@ -1782,7 +1782,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
@ -1919,7 +1919,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -2024,7 +2024,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("org1", "org1").Aggregate,
|
&user.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -2123,7 +2123,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -2244,7 +2244,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
@ -317,8 +317,7 @@ type HumanU2FLoginReadModel struct {
|
|||||||
Challenge string
|
Challenge string
|
||||||
AllowedCredentialIDs [][]byte
|
AllowedCredentialIDs [][]byte
|
||||||
UserVerification domain.UserVerificationRequirement
|
UserVerification domain.UserVerificationRequirement
|
||||||
User
|
State domain.UserState
|
||||||
State domain.UserState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHumanU2FLoginReadModel(userID, authReqID, resourceOwner string) *HumanU2FLoginReadModel {
|
func NewHumanU2FLoginReadModel(userID, authReqID, resourceOwner string) *HumanU2FLoginReadModel {
|
||||||
|
@ -13,11 +13,11 @@ func (c *Commands) AddMachine(ctx context.Context, orgID string, machine *domain
|
|||||||
if !machine.IsValid() {
|
if !machine.IsValid() {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-bm9Ds", "Errors.User.Invalid")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-bm9Ds", "Errors.User.Invalid")
|
||||||
}
|
}
|
||||||
orgIAMPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
domainPolicy, err := c.getOrgDomainPolicy(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.DomainPolicy.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.DomainPolicy.NotFound")
|
||||||
}
|
}
|
||||||
if !orgIAMPolicy.UserLoginMustBeDomain {
|
if !domainPolicy.UserLoginMustBeDomain {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0ds", "Errors.User.Invalid")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0ds", "Errors.User.Invalid")
|
||||||
}
|
}
|
||||||
userID, err := c.idGenerator.Next()
|
userID, err := c.idGenerator.Next()
|
||||||
@ -33,7 +33,7 @@ func (c *Commands) AddMachine(ctx context.Context, orgID string, machine *domain
|
|||||||
machine.Username,
|
machine.Username,
|
||||||
machine.Name,
|
machine.Name,
|
||||||
machine.Description,
|
machine.Description,
|
||||||
orgIAMPolicy.UserLoginMustBeDomain,
|
domainPolicy.UserLoginMustBeDomain,
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -83,7 +83,7 @@ func TestCommandSide_AddMachine(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
@ -110,7 +110,7 @@ func TestCommandSide_AddMachine(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewOrgDomainPolicyAddedEvent(context.Background(),
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
@ -128,7 +128,7 @@ func UserAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregat
|
|||||||
|
|
||||||
func CheckDomainPolicyForUserName(userName string, policy *domain.DomainPolicy) error {
|
func CheckDomainPolicyForUserName(userName string, policy *domain.DomainPolicy) error {
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
return caos_errors.ThrowPreconditionFailed(nil, "COMMAND-3Mb9s", "Errors.Users.OrgIamPolicyNil")
|
return caos_errors.ThrowPreconditionFailed(nil, "COMMAND-3Mb9s", "Errors.Users.DomainPolicyNil")
|
||||||
}
|
}
|
||||||
if policy.UserLoginMustBeDomain && strings.Contains(userName, "@") {
|
if policy.UserLoginMustBeDomain && strings.Contains(userName, "@") {
|
||||||
return caos_errors.ThrowPreconditionFailed(nil, "COMMAND-4M9vs", "Errors.User.EmailAsUsernameNotAllowed")
|
return caos_errors.ThrowPreconditionFailed(nil, "COMMAND-4M9vs", "Errors.User.EmailAsUsernameNotAllowed")
|
||||||
|
@ -202,7 +202,7 @@ func TestCommandSide_UsernameChange(t *testing.T) {
|
|||||||
expectFilter(),
|
expectFilter(),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -244,7 +244,7 @@ func TestCommandSide_UsernameChange(t *testing.T) {
|
|||||||
expectFilter(),
|
expectFilter(),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1026,7 +1026,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
|
|||||||
expectFilter(),
|
expectFilter(),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1090,7 +1090,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
|
|||||||
expectFilter(),
|
expectFilter(),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@ -1147,7 +1147,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
|
|||||||
expectFilter(),
|
expectFilter(),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewInstnaceDomainPolicyAddedEvent(context.Background(),
|
instance.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
36
internal/command/v2/command.go
Normal file
36
internal/command/v2/command.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/action"
|
||||||
|
iam_repo "github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
"github.com/caos/zitadel/internal/repository/keypair"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
proj_repo "github.com/caos/zitadel/internal/repository/project"
|
||||||
|
usr_repo "github.com/caos/zitadel/internal/repository/user"
|
||||||
|
usr_grant_repo "github.com/caos/zitadel/internal/repository/usergrant"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
es *eventstore.Eventstore
|
||||||
|
userPasswordAlg crypto.HashAlgorithm
|
||||||
|
iamDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(es *eventstore.Eventstore, iamDomain string, defaults sd.SystemDefaults) *Command {
|
||||||
|
iam_repo.RegisterEventMappers(es)
|
||||||
|
org.RegisterEventMappers(es)
|
||||||
|
usr_repo.RegisterEventMappers(es)
|
||||||
|
usr_grant_repo.RegisterEventMappers(es)
|
||||||
|
proj_repo.RegisterEventMappers(es)
|
||||||
|
keypair.RegisterEventMappers(es)
|
||||||
|
action.RegisterEventMappers(es)
|
||||||
|
|
||||||
|
return &Command{
|
||||||
|
es: es,
|
||||||
|
iamDomain: iamDomain,
|
||||||
|
userPasswordAlg: crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost),
|
||||||
|
}
|
||||||
|
}
|
290
internal/command/v2/instance.go
Normal file
290
internal/command/v2/instance.go
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
"github.com/caos/zitadel/internal/api/ui/console"
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/id"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
zitadelProjectName = "ZITADEL"
|
||||||
|
mgmtAppName = "Management-API"
|
||||||
|
adminAppName = "Admin-API"
|
||||||
|
authAppName = "Auth-API"
|
||||||
|
consoleAppName = "Console"
|
||||||
|
consoleRedirectPath = console.HandlerPrefix + "/auth/callback"
|
||||||
|
consolePostLogoutPath = console.HandlerPrefix + "/signedout"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstanceSetup struct {
|
||||||
|
Org OrgSetup
|
||||||
|
Zitadel ZitadelConfig
|
||||||
|
PasswordComplexityPolicy struct {
|
||||||
|
MinLength uint64
|
||||||
|
HasLowercase bool
|
||||||
|
HasUppercase bool
|
||||||
|
HasNumber bool
|
||||||
|
HasSymbol bool
|
||||||
|
}
|
||||||
|
PasswordAgePolicy struct {
|
||||||
|
ExpireWarnDays uint64
|
||||||
|
MaxAgeDays uint64
|
||||||
|
}
|
||||||
|
DomainPolicy struct {
|
||||||
|
UserLoginMustBeDomain bool
|
||||||
|
}
|
||||||
|
LoginPolicy struct {
|
||||||
|
AllowUsernamePassword bool
|
||||||
|
AllowRegister bool
|
||||||
|
AllowExternalIDP bool
|
||||||
|
ForceMFA bool
|
||||||
|
HidePasswordReset bool
|
||||||
|
PasswordlessType domain.PasswordlessType
|
||||||
|
PasswordCheckLifetime time.Duration
|
||||||
|
ExternalLoginCheckLifetime time.Duration
|
||||||
|
MfaInitSkipLifetime time.Duration
|
||||||
|
SecondFactorCheckLifetime time.Duration
|
||||||
|
MultiFactorCheckLifetime time.Duration
|
||||||
|
}
|
||||||
|
PrivacyPolicy struct {
|
||||||
|
TOSLink string
|
||||||
|
PrivacyLink string
|
||||||
|
HelpLink string
|
||||||
|
}
|
||||||
|
LockoutPolicy struct {
|
||||||
|
MaxAttempts uint64
|
||||||
|
ShouldShowLockoutFailure bool
|
||||||
|
}
|
||||||
|
EmailTemplate []byte
|
||||||
|
MessageTexts []*domain.CustomMessageText
|
||||||
|
}
|
||||||
|
|
||||||
|
type ZitadelConfig struct {
|
||||||
|
IsDevMode bool
|
||||||
|
BaseURL string
|
||||||
|
|
||||||
|
projectID string
|
||||||
|
mgmtID string
|
||||||
|
mgmtClientID string
|
||||||
|
adminID string
|
||||||
|
adminClientID string
|
||||||
|
authID string
|
||||||
|
authClientID string
|
||||||
|
consoleID string
|
||||||
|
consoleClientID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InstanceSetup) generateIDs() (err error) {
|
||||||
|
s.Zitadel.projectID, err = id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Zitadel.mgmtID, err = id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Zitadel.mgmtClientID, err = domain.NewClientID(id.SonyFlakeGenerator, zitadelProjectName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Zitadel.adminID, err = id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Zitadel.adminClientID, err = domain.NewClientID(id.SonyFlakeGenerator, zitadelProjectName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Zitadel.authID, err = id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Zitadel.authClientID, err = domain.NewClientID(id.SonyFlakeGenerator, zitadelProjectName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Zitadel.consoleID, err = id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Zitadel.consoleClientID, err = domain.NewClientID(id.SonyFlakeGenerator, zitadelProjectName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*domain.ObjectDetails, error) {
|
||||||
|
// TODO
|
||||||
|
// instanceID, err := id.SonyFlakeGenerator.Next()
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
ctx = authz.SetCtxData(authz.WithInstance(ctx, authz.Instance{ID: "system"}), authz.CtxData{OrgID: domain.IAMID, ResourceOwner: domain.IAMID})
|
||||||
|
|
||||||
|
orgID, err := id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = setup.generateIDs(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
setup.Org.Human.PasswordChangeRequired = true
|
||||||
|
|
||||||
|
instanceAgg := instance.NewAggregate()
|
||||||
|
orgAgg := org.NewAggregate(orgID, orgID)
|
||||||
|
userAgg := user.NewAggregate(userID, orgID)
|
||||||
|
projectAgg := project.NewAggregate(setup.Zitadel.projectID, orgID)
|
||||||
|
|
||||||
|
validations := []preparation.Validation{
|
||||||
|
AddPasswordComplexityPolicy(
|
||||||
|
instanceAgg,
|
||||||
|
setup.PasswordComplexityPolicy.MinLength,
|
||||||
|
setup.PasswordComplexityPolicy.HasLowercase,
|
||||||
|
setup.PasswordComplexityPolicy.HasUppercase,
|
||||||
|
setup.PasswordComplexityPolicy.HasNumber,
|
||||||
|
setup.PasswordComplexityPolicy.HasSymbol,
|
||||||
|
),
|
||||||
|
AddPasswordAgePolicy(
|
||||||
|
instanceAgg,
|
||||||
|
setup.PasswordAgePolicy.ExpireWarnDays,
|
||||||
|
setup.PasswordAgePolicy.MaxAgeDays,
|
||||||
|
),
|
||||||
|
AddDefaultDomainPolicy(
|
||||||
|
instanceAgg,
|
||||||
|
setup.DomainPolicy.UserLoginMustBeDomain,
|
||||||
|
),
|
||||||
|
AddDefaultLoginPolicy(
|
||||||
|
instanceAgg,
|
||||||
|
setup.LoginPolicy.AllowUsernamePassword,
|
||||||
|
setup.LoginPolicy.AllowRegister,
|
||||||
|
setup.LoginPolicy.AllowExternalIDP,
|
||||||
|
setup.LoginPolicy.ForceMFA,
|
||||||
|
setup.LoginPolicy.HidePasswordReset,
|
||||||
|
setup.LoginPolicy.PasswordlessType,
|
||||||
|
setup.LoginPolicy.PasswordCheckLifetime,
|
||||||
|
setup.LoginPolicy.ExternalLoginCheckLifetime,
|
||||||
|
setup.LoginPolicy.MfaInitSkipLifetime,
|
||||||
|
setup.LoginPolicy.SecondFactorCheckLifetime,
|
||||||
|
setup.LoginPolicy.MultiFactorCheckLifetime,
|
||||||
|
),
|
||||||
|
AddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeOTP),
|
||||||
|
AddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeU2F),
|
||||||
|
AddMultiFactorToDefaultLoginPolicy(instanceAgg, domain.MultiFactorTypeU2FWithPIN),
|
||||||
|
|
||||||
|
AddPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink),
|
||||||
|
AddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure),
|
||||||
|
|
||||||
|
AddEmailTemplate(instanceAgg, setup.EmailTemplate),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, msg := range setup.MessageTexts {
|
||||||
|
validations = append(validations, SetInstanceCustomTexts(instanceAgg, msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
validations = append(validations,
|
||||||
|
AddOrg(orgAgg, setup.Org.Name, command.iamDomain),
|
||||||
|
AddHumanCommand(userAgg, &setup.Org.Human, command.userPasswordAlg),
|
||||||
|
AddOrgMember(orgAgg, userID, domain.RoleOrgOwner),
|
||||||
|
|
||||||
|
AddProject(projectAgg, zitadelProjectName, userID, false, false, false, domain.PrivateLabelingSettingUnspecified),
|
||||||
|
|
||||||
|
SetIAMProject(instanceAgg, projectAgg.ID),
|
||||||
|
|
||||||
|
AddAPIApp(
|
||||||
|
*projectAgg,
|
||||||
|
setup.Zitadel.mgmtID,
|
||||||
|
mgmtAppName,
|
||||||
|
setup.Zitadel.mgmtClientID,
|
||||||
|
nil,
|
||||||
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
|
),
|
||||||
|
|
||||||
|
AddAPIApp(
|
||||||
|
*projectAgg,
|
||||||
|
setup.Zitadel.adminID,
|
||||||
|
adminAppName,
|
||||||
|
setup.Zitadel.adminClientID,
|
||||||
|
nil,
|
||||||
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
|
),
|
||||||
|
|
||||||
|
AddAPIApp(
|
||||||
|
*projectAgg,
|
||||||
|
setup.Zitadel.authID,
|
||||||
|
authAppName,
|
||||||
|
setup.Zitadel.authClientID,
|
||||||
|
nil,
|
||||||
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
|
),
|
||||||
|
|
||||||
|
AddOIDCApp(
|
||||||
|
*projectAgg,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
setup.Zitadel.consoleID,
|
||||||
|
consoleAppName,
|
||||||
|
setup.Zitadel.consoleClientID,
|
||||||
|
nil,
|
||||||
|
[]string{setup.Zitadel.BaseURL + consoleRedirectPath},
|
||||||
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
domain.OIDCApplicationTypeUserAgent,
|
||||||
|
domain.OIDCAuthMethodTypeNone,
|
||||||
|
[]string{setup.Zitadel.BaseURL + consolePostLogoutPath},
|
||||||
|
setup.Zitadel.IsDevMode,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
cmds, err := preparation.PrepareCommands(ctx, command.es.Filter, validations...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
events, err := command.es.Push(ctx, cmds...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &domain.ObjectDetails{
|
||||||
|
Sequence: events[len(events)-1].Sequence(),
|
||||||
|
EventDate: events[len(events)-1].CreationDate(),
|
||||||
|
ResourceOwner: orgID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetIAMProject defines the commands to set the id of the IAM project onto the instance
|
||||||
|
func SetIAMProject(a *instance.Aggregate, projectID string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewIAMProjectSetEvent(ctx, &a.Aggregate, projectID),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
25
internal/command/v2/instance_domain_policy.go
Normal file
25
internal/command/v2/instance_domain_policy.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddDefaultDomainPolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
userLoginMustBeDomain bool,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewDomainPolicyAddedEvent(ctx, &a.Aggregate,
|
||||||
|
userLoginMustBeDomain,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
107
internal/command/v2/instance_email_template.go
Normal file
107
internal/command/v2/instance_email_template.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command"
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddEmailTemplate(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
tempalte []byte,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewMailTemplateAddedEvent(ctx, &a.Aggregate,
|
||||||
|
tempalte,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetInstanceCustomTexts(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
msg *domain.CustomMessageText,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
existing, err := existingInstanceCustomMessageText(ctx, filter, msg.MessageTextType, msg.Language)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds := make([]eventstore.Command, 0, 7)
|
||||||
|
if existing.Greeting != msg.Greeting {
|
||||||
|
if msg.Greeting != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageGreeting, msg.Greeting, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageGreeting, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existing.Subject != msg.Subject {
|
||||||
|
if msg.Subject != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageSubject, msg.Subject, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageSubject, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existing.Title != msg.Title {
|
||||||
|
if msg.Title != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageTitle, msg.Title, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageTitle, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existing.PreHeader != msg.PreHeader {
|
||||||
|
if msg.PreHeader != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessagePreHeader, msg.PreHeader, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessagePreHeader, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existing.Text != msg.Text {
|
||||||
|
if msg.Text != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageText, msg.Text, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageText, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existing.ButtonText != msg.ButtonText {
|
||||||
|
if msg.ButtonText != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageButtonText, msg.ButtonText, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageButtonText, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existing.FooterText != msg.FooterText {
|
||||||
|
if msg.FooterText != "" {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageFooterText, msg.FooterText, msg.Language))
|
||||||
|
} else {
|
||||||
|
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageFooterText, msg.Language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: what if no text changed? len(events) == 0
|
||||||
|
return cmds, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func existingInstanceCustomMessageText(ctx context.Context, filter preparation.FilterToQueryReducer, textType string, lang language.Tag) (*command.InstanceCustomMessageTextWriteModel, error) {
|
||||||
|
writeModel := command.NewInstanceCustomMessageTextWriteModel(textType, lang)
|
||||||
|
events, err := filter(ctx, writeModel.Query())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
writeModel.AppendEvents(events...)
|
||||||
|
writeModel.Reduce()
|
||||||
|
return writeModel, nil
|
||||||
|
}
|
45
internal/command/v2/instance_label_policy.go
Normal file
45
internal/command/v2/instance_label_policy.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddDefaultLabelPolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
primaryColor,
|
||||||
|
backgroundColor,
|
||||||
|
warnColor,
|
||||||
|
fontColor,
|
||||||
|
primaryColorDark,
|
||||||
|
backgroundColorDark,
|
||||||
|
warnColorDark,
|
||||||
|
fontColorDark string,
|
||||||
|
hideLoginNameSuffix,
|
||||||
|
errorMsgPopup,
|
||||||
|
disableWatermark bool,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewLabelPolicyAddedEvent(ctx, &a.Aggregate,
|
||||||
|
primaryColor,
|
||||||
|
backgroundColor,
|
||||||
|
warnColor,
|
||||||
|
fontColor,
|
||||||
|
primaryColorDark,
|
||||||
|
backgroundColorDark,
|
||||||
|
warnColorDark,
|
||||||
|
fontColorDark,
|
||||||
|
hideLoginNameSuffix,
|
||||||
|
errorMsgPopup,
|
||||||
|
disableWatermark,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
24
internal/command/v2/instance_lockout_policy.go
Normal file
24
internal/command/v2/instance_lockout_policy.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddDefaultLockoutPolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
maxAttempts uint64,
|
||||||
|
showLockoutFailure bool,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewLockoutPolicyAddedEvent(ctx, &a.Aggregate, maxAttempts, showLockoutFailure),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
69
internal/command/v2/instance_login_policy.go
Normal file
69
internal/command/v2/instance_login_policy.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddDefaultLoginPolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
allowUsernamePassword bool,
|
||||||
|
allowRegister bool,
|
||||||
|
allowExternalIDP bool,
|
||||||
|
forceMFA bool,
|
||||||
|
hidePasswordReset bool,
|
||||||
|
passwordlessType domain.PasswordlessType,
|
||||||
|
passwordCheckLifetime time.Duration,
|
||||||
|
externalLoginCheckLifetime time.Duration,
|
||||||
|
mfaInitSkipLifetime time.Duration,
|
||||||
|
secondFactorCheckLifetime time.Duration,
|
||||||
|
multiFactorCheckLifetime time.Duration,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewLoginPolicyAddedEvent(ctx, &a.Aggregate,
|
||||||
|
allowUsernamePassword,
|
||||||
|
allowRegister,
|
||||||
|
allowExternalIDP,
|
||||||
|
forceMFA,
|
||||||
|
hidePasswordReset,
|
||||||
|
passwordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSecondFactorToDefaultLoginPolicy(a *instance.Aggregate, factor domain.SecondFactorType) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewLoginPolicySecondFactorAddedEvent(ctx, &a.Aggregate, factor),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddMultiFactorToDefaultLoginPolicy(a *instance.Aggregate, factor domain.MultiFactorType) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewLoginPolicyMultiFactorAddedEvent(ctx, &a.Aggregate, factor),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
27
internal/command/v2/instance_password_age_policy.go
Normal file
27
internal/command/v2/instance_password_age_policy.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddPasswordAgePolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
expireWarnDays,
|
||||||
|
maxAgeDays uint64,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewPasswordAgePolicyAddedEvent(ctx, &a.Aggregate,
|
||||||
|
expireWarnDays,
|
||||||
|
maxAgeDays,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
33
internal/command/v2/instance_password_complexity_policy.go
Normal file
33
internal/command/v2/instance_password_complexity_policy.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddPasswordComplexityPolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
minLength uint64,
|
||||||
|
hasLowercase,
|
||||||
|
hasUppercase,
|
||||||
|
hasNumber,
|
||||||
|
hasSymbol bool,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewPasswordComplexityPolicyAddedEvent(ctx, &a.Aggregate,
|
||||||
|
minLength,
|
||||||
|
hasLowercase,
|
||||||
|
hasUppercase,
|
||||||
|
hasNumber,
|
||||||
|
hasSymbol,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
25
internal/command/v2/instance_privacy_policy.go
Normal file
25
internal/command/v2/instance_privacy_policy.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddPrivacyPolicy(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
tosLink,
|
||||||
|
privacyLink,
|
||||||
|
helpLink string,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewPrivacyPolicyAddedEvent(ctx, &a.Aggregate, tosLink, privacyLink, helpLink),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
72
internal/command/v2/org.go
Normal file
72
internal/command/v2/org.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/id"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
user_repo "github.com/caos/zitadel/internal/repository/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgSetup struct {
|
||||||
|
Name string
|
||||||
|
Human AddHuman
|
||||||
|
}
|
||||||
|
|
||||||
|
func (command *Command) SetUpOrg(ctx context.Context, o *OrgSetup) (*domain.ObjectDetails, error) {
|
||||||
|
orgID, err := id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := id.SonyFlakeGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
orgAgg := org.NewAggregate(orgID, orgID)
|
||||||
|
userAgg := user_repo.NewAggregate(userID, orgID)
|
||||||
|
|
||||||
|
cmds, err := preparation.PrepareCommands(ctx, command.es.Filter,
|
||||||
|
AddOrg(orgAgg, o.Name, command.iamDomain),
|
||||||
|
AddHumanCommand(userAgg, &o.Human, command.userPasswordAlg),
|
||||||
|
AddOrgMember(orgAgg, userID, domain.RoleOrgOwner),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
events, err := command.es.Push(ctx, cmds...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &domain.ObjectDetails{
|
||||||
|
Sequence: events[len(events)-1].Sequence(),
|
||||||
|
EventDate: events[len(events)-1].CreationDate(),
|
||||||
|
ResourceOwner: orgID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//AddOrg defines the commands to create a new org,
|
||||||
|
// this includes the verified default domain
|
||||||
|
func AddOrg(a *org.Aggregate, name, iamDomain string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if name = strings.TrimSpace(name); name == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
defaultDomain := domain.NewIAMDomainName(name, iamDomain)
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{
|
||||||
|
org.NewOrgAddedEvent(ctx, &a.Aggregate, name),
|
||||||
|
org.NewDomainAddedEvent(ctx, &a.Aggregate, defaultDomain),
|
||||||
|
org.NewDomainVerifiedEvent(ctx, &a.Aggregate, defaultDomain),
|
||||||
|
org.NewDomainPrimarySetEvent(ctx, &a.Aggregate, defaultDomain),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
46
internal/command/v2/org_domain.go
Normal file
46
internal/command/v2/org_domain.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddOrgDomain(a *org.Aggregate, domain string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if domain = strings.TrimSpace(domain); domain == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "ORG-r3h4J", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{org.NewDomainAddedEvent(ctx, &a.Aggregate, domain)}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyOrgDomain(a *org.Aggregate, domain string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if domain = strings.TrimSpace(domain); domain == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "ORG-yqlVQ", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists
|
||||||
|
return []eventstore.Command{org.NewDomainVerifiedEvent(ctx, &a.Aggregate, domain)}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetPrimaryOrgDomain(a *org.Aggregate, domain string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if domain = strings.TrimSpace(domain); domain == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "ORG-gmNqY", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
//TODO: check if already exists and verified
|
||||||
|
return []eventstore.Command{org.NewDomainPrimarySetEvent(ctx, &a.Aggregate, domain)}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
133
internal/command/v2/org_domain_test.go
Normal file
133
internal/command/v2/org_domain_test.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddDomain(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *org.Aggregate
|
||||||
|
domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid domain",
|
||||||
|
args: args{
|
||||||
|
a: org.NewAggregate("test", "test"),
|
||||||
|
domain: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "ORG-r3h4J", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: org.NewAggregate("test", "test"),
|
||||||
|
domain: "domain",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
org.NewDomainAddedEvent(context.Background(), &org.NewAggregate("test", "test").Aggregate, "domain"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, AddOrgDomain(tt.args.a, tt.args.domain), nil, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyDomain(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *org.Aggregate
|
||||||
|
domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid domain",
|
||||||
|
args: args{
|
||||||
|
a: org.NewAggregate("test", "test"),
|
||||||
|
domain: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "ORG-yqlVQ", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: org.NewAggregate("test", "test"),
|
||||||
|
domain: "domain",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
org.NewDomainVerifiedEvent(context.Background(), &org.NewAggregate("test", "test").Aggregate, "domain"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, VerifyOrgDomain(tt.args.a, tt.args.domain), nil, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetDomainPrimary(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *org.Aggregate
|
||||||
|
domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid domain",
|
||||||
|
args: args{
|
||||||
|
a: org.NewAggregate("test", "test"),
|
||||||
|
domain: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "ORG-gmNqY", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: org.NewAggregate("test", "test"),
|
||||||
|
domain: "domain",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
org.NewDomainPrimarySetEvent(context.Background(), &org.NewAggregate("test", "test").Aggregate, "domain"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, SetPrimaryOrgDomain(tt.args.a, tt.args.domain), nil, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
65
internal/command/v2/org_member.go
Normal file
65
internal/command/v2/org_member.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddOrgMember(a *org.Aggregate, userID string, roles ...string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if userID == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "ORG-4Mlfs", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
// TODO: check roles
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
if exists, err := ExistsUser(ctx, filter, userID, a.ID); err != nil || !exists {
|
||||||
|
return nil, errors.ThrowNotFound(err, "ORG-GoXOn", "Errors.User.NotFound")
|
||||||
|
}
|
||||||
|
if isMember, err := IsOrgMember(ctx, filter, a.ID, userID); err != nil || isMember {
|
||||||
|
return nil, errors.ThrowAlreadyExists(err, "ORG-poWwe", "Errors.Org.Member.AlreadyExists")
|
||||||
|
}
|
||||||
|
return []eventstore.Command{org.NewMemberAddedEvent(ctx, &a.Aggregate, userID, roles...)}, nil
|
||||||
|
},
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsOrgMember(ctx context.Context, filter preparation.FilterToQueryReducer, orgID, userID string) (isMember bool, err error) {
|
||||||
|
events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||||
|
ResourceOwner(orgID).
|
||||||
|
OrderAsc().
|
||||||
|
AddQuery().
|
||||||
|
AggregateIDs(orgID).
|
||||||
|
AggregateTypes(org.AggregateType).
|
||||||
|
EventTypes(
|
||||||
|
org.MemberAddedEventType,
|
||||||
|
org.MemberRemovedEventType,
|
||||||
|
org.MemberCascadeRemovedEventType,
|
||||||
|
).Builder())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
switch e := event.(type) {
|
||||||
|
case *org.MemberAddedEvent:
|
||||||
|
if e.UserID == userID {
|
||||||
|
isMember = true
|
||||||
|
}
|
||||||
|
case *org.MemberRemovedEvent:
|
||||||
|
if e.UserID == userID {
|
||||||
|
isMember = false
|
||||||
|
}
|
||||||
|
case *org.MemberCascadeRemovedEvent:
|
||||||
|
if e.UserID == userID {
|
||||||
|
isMember = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isMember, nil
|
||||||
|
}
|
249
internal/command/v2/org_member_test.go
Normal file
249
internal/command/v2/org_member_test.go
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddMember(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *org.Aggregate
|
||||||
|
userID string
|
||||||
|
roles []string
|
||||||
|
filter preparation.FilterToQueryReducer
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
agg := org.NewAggregate("test", "test")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no user id",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
userID: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "ORG-4Mlfs", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// name: "TODO: invalid roles",
|
||||||
|
// args: args{
|
||||||
|
// a: agg,
|
||||||
|
// userID: "",
|
||||||
|
// roles: []string{""},
|
||||||
|
// },
|
||||||
|
// want: preparation.Want{
|
||||||
|
// ValidationErr: errors.ThrowInvalidArgument(nil, "ORG-4Mlfs", "Errors.Invalid.Argument"),
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: "user not exists",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
userID: "userID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
CreateErr: errors.ThrowNotFound(nil, "ORG-GoXOn", "Errors.User.NotFound"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "already member",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
userID: "userID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
user.NewMachineAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&user.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"userName",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}).
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
org.NewMemberAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&org.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"userID",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
CreateErr: errors.ThrowAlreadyExists(nil, "ORG-poWwe", "Errors.Org.Member.AlreadyExists"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
userID: "userID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
user.NewMachineAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&user.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"userName",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}).
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
org.NewMemberAddedEvent(ctx, &agg.Aggregate, "userID"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, AddOrgMember(tt.args.a, tt.args.userID, tt.args.roles...), tt.args.filter, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsMember(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
filter preparation.FilterToQueryReducer
|
||||||
|
orgID string
|
||||||
|
userID string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantExists bool
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no events",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{}, nil
|
||||||
|
},
|
||||||
|
orgID: "orgID",
|
||||||
|
userID: "userID",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "member added",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
org.NewMemberAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&org.NewAggregate("orgID", "ro").Aggregate,
|
||||||
|
"userID",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
orgID: "orgID",
|
||||||
|
userID: "userID",
|
||||||
|
},
|
||||||
|
wantExists: true,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "member removed",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
org.NewMemberAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&org.NewAggregate("orgID", "ro").Aggregate,
|
||||||
|
"userID",
|
||||||
|
),
|
||||||
|
org.NewMemberRemovedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&org.NewAggregate("orgID", "ro").Aggregate,
|
||||||
|
"userID",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
orgID: "orgID",
|
||||||
|
userID: "userID",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "member cascade removed",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
org.NewMemberAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&org.NewAggregate("orgID", "ro").Aggregate,
|
||||||
|
"userID",
|
||||||
|
),
|
||||||
|
org.NewMemberCascadeRemovedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&org.NewAggregate("orgID", "ro").Aggregate,
|
||||||
|
"userID",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
orgID: "orgID",
|
||||||
|
userID: "userID",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error durring filter",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, errors.ThrowInternal(nil, "PROJE-Op26p", "Errors.Internal")
|
||||||
|
},
|
||||||
|
orgID: "orgID",
|
||||||
|
userID: "userID",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotExists, err := IsOrgMember(context.Background(), tt.args.filter, tt.args.orgID, tt.args.userID)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("ExistsUser() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotExists != tt.wantExists {
|
||||||
|
t.Errorf("ExistsUser() = %v, want %v", gotExists, tt.wantExists)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
57
internal/command/v2/org_test.go
Normal file
57
internal/command/v2/org_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddOrg(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *org.Aggregate
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
agg := org.NewAggregate("test", "test")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid domain",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
name: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
name: "caos ag",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
org.NewOrgAddedEvent(ctx, &agg.Aggregate, "caos ag"),
|
||||||
|
org.NewDomainAddedEvent(ctx, &agg.Aggregate, "caos-ag.localhost"),
|
||||||
|
org.NewDomainVerifiedEvent(ctx, &agg.Aggregate, "caos-ag.localhost"),
|
||||||
|
org.NewDomainPrimarySetEvent(ctx, &agg.Aggregate, "caos-ag.localhost"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, AddOrg(tt.args.a, tt.args.name, "localhost"), nil, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
80
internal/command/v2/preparation/command.go
Normal file
80
internal/command/v2/preparation/command.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package preparation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validation of the input values of the command and if correct returns
|
||||||
|
// the function to create commands or if not valid an error
|
||||||
|
type Validation func() (CreateCommands, error)
|
||||||
|
|
||||||
|
// CreateCommands builds the commands
|
||||||
|
// the filter param is an extended version of the eventstore filter method
|
||||||
|
// it filters for events including the commands on the current context
|
||||||
|
type CreateCommands func(context.Context, FilterToQueryReducer) ([]eventstore.Command, error)
|
||||||
|
|
||||||
|
// FilterToQueryReducer is an abstraction of the eventstore method
|
||||||
|
type FilterToQueryReducer func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//ErrNotExecutable is thrown if no command creator was created
|
||||||
|
ErrNotExecutable = errors.ThrowInvalidArgument(nil, "PREPA-pH70n", "Errors.Internal")
|
||||||
|
)
|
||||||
|
|
||||||
|
// PrepareCommands checks the passed validations and if ok creates the commands
|
||||||
|
func PrepareCommands(ctx context.Context, filter FilterToQueryReducer, validations ...Validation) (cmds []eventstore.Command, err error) {
|
||||||
|
commanders, err := validate(validations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return create(ctx, filter, commanders)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validate(validations []Validation) ([]CreateCommands, error) {
|
||||||
|
creators := make([]CreateCommands, 0, len(validations))
|
||||||
|
|
||||||
|
for _, validate := range validations {
|
||||||
|
cmds, err := validate()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
creators = append(creators, cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(creators) == 0 {
|
||||||
|
return nil, ErrNotExecutable
|
||||||
|
}
|
||||||
|
return creators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func create(ctx context.Context, filter FilterToQueryReducer, commanders []CreateCommands) (cmds []eventstore.Command, err error) {
|
||||||
|
for _, command := range commanders {
|
||||||
|
cmd, err := command(ctx, transactionFilter(filter, cmds))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmds = append(cmds, cmd...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func transactionFilter(filter FilterToQueryReducer, commands []eventstore.Command) FilterToQueryReducer {
|
||||||
|
return func(ctx context.Context, query *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
events, err := filter(ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, command := range commands {
|
||||||
|
event := command.(eventstore.Event)
|
||||||
|
if !query.Matches(event, len(events)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
events = append(events, event)
|
||||||
|
}
|
||||||
|
return events, nil
|
||||||
|
}
|
||||||
|
}
|
176
internal/command/v2/preparation/command_test.go
Normal file
176
internal/command/v2/preparation/command_test.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package preparation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errTest = errors.New("test")
|
||||||
|
|
||||||
|
func Test_validate(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
validations []Validation
|
||||||
|
}
|
||||||
|
type want struct {
|
||||||
|
len int
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no validations",
|
||||||
|
args: args{},
|
||||||
|
want: want{
|
||||||
|
err: ErrNotExecutable,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error in validation",
|
||||||
|
args: args{
|
||||||
|
validations: []Validation{
|
||||||
|
func() (CreateCommands, error) {
|
||||||
|
return nil, errTest
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
err: errTest,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
validations: []Validation{
|
||||||
|
func() (CreateCommands, error) {
|
||||||
|
return func(_ context.Context, _ FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return nil, nil
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := validate(tt.args.validations)
|
||||||
|
if !errors.Is(err, tt.want.err) {
|
||||||
|
t.Errorf("validate() error = %v, wantErr %v", err, tt.want.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(got) != tt.want.len {
|
||||||
|
t.Errorf("validate() len = %v, want %v", len(got), tt.want.len)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_create(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
commanders []CreateCommands
|
||||||
|
}
|
||||||
|
type want struct {
|
||||||
|
err error
|
||||||
|
len int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "error in command",
|
||||||
|
want: want{
|
||||||
|
err: errTest,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
commanders: []CreateCommands{
|
||||||
|
func(_ context.Context, _ FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return nil, errTest
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no commands",
|
||||||
|
want: want{},
|
||||||
|
args: args{
|
||||||
|
commanders: []CreateCommands{
|
||||||
|
func(_ context.Context, _ FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple commands",
|
||||||
|
want: want{
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
commanders: []CreateCommands{
|
||||||
|
func(_ context.Context, _ FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{new(testCommand), new(testCommand)}, nil
|
||||||
|
},
|
||||||
|
func(_ context.Context, _ FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{new(testCommand)}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotCmds, err := create(context.Background(), nil, tt.args.commanders)
|
||||||
|
if !errors.Is(err, tt.want.err) {
|
||||||
|
t.Errorf("create() error = %v, wantErr %v", err, tt.want.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(gotCmds) != tt.want.len {
|
||||||
|
t.Errorf("create() len = %d, want %d", len(gotCmds), tt.want.len)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_transactionFilter(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
filter FilterToQueryReducer
|
||||||
|
commands []eventstore.Command
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want FilterToQueryReducer
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := transactionFilter(tt.args.filter, tt.args.commands); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("transactionFilter() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCommand struct {
|
||||||
|
eventstore.BaseEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testCommand) Data() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testCommand) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||||
|
return nil
|
||||||
|
}
|
81
internal/command/v2/preparation_test.go
Normal file
81
internal/command/v2/preparation_test.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// this is a helper file for tests
|
||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Want represents the expected values for each step
|
||||||
|
type Want struct {
|
||||||
|
ValidationErr error
|
||||||
|
CreateErr error
|
||||||
|
Commands []eventstore.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
//AssertValidation checks if the validation works as inteded
|
||||||
|
func AssertValidation(t *testing.T, validation preparation.Validation, filter preparation.FilterToQueryReducer, want Want) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
creates, err := validation()
|
||||||
|
if !errors.Is(err, want.ValidationErr) {
|
||||||
|
t.Errorf("wrong validation err = %v, want %v", err, want.ValidationErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmds, err := creates(context.Background(), filter)
|
||||||
|
if !errors.Is(err, want.CreateErr) {
|
||||||
|
t.Errorf("wrong create err = %v, want %v", err, want.CreateErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cmds) != len(want.Commands) {
|
||||||
|
t.Errorf("wrong length of commands = %v, want %v", eventTypes(cmds), eventTypes(want.Commands))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, cmd := range want.Commands {
|
||||||
|
if !reflect.DeepEqual(cmd, cmds[i]) {
|
||||||
|
t.Errorf("unexpected command: = %v, want %v", cmds[i], cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func eventTypes(cmds []eventstore.Command) []eventstore.EventType {
|
||||||
|
types := make([]eventstore.EventType, len(cmds))
|
||||||
|
for i, cmd := range cmds {
|
||||||
|
types[i] = cmd.Type()
|
||||||
|
}
|
||||||
|
return types
|
||||||
|
}
|
||||||
|
|
||||||
|
type MultiFilter struct {
|
||||||
|
count int
|
||||||
|
filters []preparation.FilterToQueryReducer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMultiFilter() *MultiFilter {
|
||||||
|
return new(MultiFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mf *MultiFilter) Append(filter preparation.FilterToQueryReducer) *MultiFilter {
|
||||||
|
mf.filters = append(mf.filters, filter)
|
||||||
|
return mf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mf *MultiFilter) Filter() preparation.FilterToQueryReducer {
|
||||||
|
return func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
mf.count++
|
||||||
|
return mf.filters[mf.count-1](ctx, queryFactory)
|
||||||
|
}
|
||||||
|
}
|
75
internal/command/v2/project.go
Normal file
75
internal/command/v2/project.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddProject(
|
||||||
|
a *project.Aggregate,
|
||||||
|
name string,
|
||||||
|
owner string,
|
||||||
|
projectRoleAssertion bool,
|
||||||
|
projectRoleCheck bool,
|
||||||
|
hasProjectCheck bool,
|
||||||
|
privateLabelingSetting domain.PrivateLabelingSetting,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if name = strings.TrimSpace(name); name == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-C01yo", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
if !privateLabelingSetting.Valid() {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-AO52V", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
if owner == "" {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "PROJE-hzxwo", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{
|
||||||
|
project.NewProjectAddedEvent(ctx, &a.Aggregate,
|
||||||
|
name,
|
||||||
|
projectRoleAssertion,
|
||||||
|
projectRoleCheck,
|
||||||
|
hasProjectCheck,
|
||||||
|
privateLabelingSetting,
|
||||||
|
),
|
||||||
|
project.NewProjectMemberAddedEvent(ctx, &a.Aggregate,
|
||||||
|
owner,
|
||||||
|
domain.RoleProjectOwner),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExistsProject(ctx context.Context, filter preparation.FilterToQueryReducer, projectID, resourceOwner string) (exists bool, err error) {
|
||||||
|
events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||||
|
ResourceOwner(resourceOwner).
|
||||||
|
OrderAsc().
|
||||||
|
AddQuery().
|
||||||
|
AggregateTypes(project.AggregateType).
|
||||||
|
AggregateIDs(projectID).
|
||||||
|
EventTypes(
|
||||||
|
project.ProjectAddedType,
|
||||||
|
project.ProjectRemovedType,
|
||||||
|
).Builder())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
switch event.(type) {
|
||||||
|
case *project.ProjectAddedEvent:
|
||||||
|
exists = true
|
||||||
|
case *project.ProjectRemovedEvent:
|
||||||
|
exists = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists, nil
|
||||||
|
}
|
155
internal/command/v2/project_app.go
Normal file
155
internal/command/v2/project_app.go
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddOIDCApp(
|
||||||
|
a project.Aggregate,
|
||||||
|
version domain.OIDCVersion,
|
||||||
|
appID,
|
||||||
|
name,
|
||||||
|
clientID string,
|
||||||
|
clientSecret *crypto.CryptoValue,
|
||||||
|
redirectUris []string,
|
||||||
|
responseTypes []domain.OIDCResponseType,
|
||||||
|
grantTypes []domain.OIDCGrantType,
|
||||||
|
applicationType domain.OIDCApplicationType,
|
||||||
|
authMethodType domain.OIDCAuthMethodType,
|
||||||
|
postLogoutRedirectUris []string,
|
||||||
|
devMode bool,
|
||||||
|
accessTokenType domain.OIDCTokenType,
|
||||||
|
accessTokenRoleAssertion bool,
|
||||||
|
idTokenRoleAssertion bool,
|
||||||
|
idTokenUserinfoAssertion bool,
|
||||||
|
clockSkew time.Duration,
|
||||||
|
additionalOrigins []string,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if appID == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-NnavI", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
if name = strings.TrimSpace(name); name == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-Fef31", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
if clientID == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-ghTsJ", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
if exists, err := ExistsProject(ctx, filter, a.ID, a.ResourceOwner); !exists || err != nil {
|
||||||
|
return nil, errors.ThrowNotFound(err, "PROJE-5LQ0U", "Errors.Project.NotFound")
|
||||||
|
}
|
||||||
|
return []eventstore.Command{
|
||||||
|
project.NewApplicationAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&a.Aggregate,
|
||||||
|
appID,
|
||||||
|
name,
|
||||||
|
),
|
||||||
|
project.NewOIDCConfigAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&a.Aggregate,
|
||||||
|
version,
|
||||||
|
appID,
|
||||||
|
clientID,
|
||||||
|
clientSecret,
|
||||||
|
redirectUris,
|
||||||
|
responseTypes,
|
||||||
|
grantTypes,
|
||||||
|
applicationType,
|
||||||
|
authMethodType,
|
||||||
|
postLogoutRedirectUris,
|
||||||
|
devMode,
|
||||||
|
accessTokenType,
|
||||||
|
accessTokenRoleAssertion,
|
||||||
|
idTokenRoleAssertion,
|
||||||
|
idTokenUserinfoAssertion,
|
||||||
|
clockSkew,
|
||||||
|
additionalOrigins,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddAPIApp(
|
||||||
|
a project.Aggregate,
|
||||||
|
appID,
|
||||||
|
name,
|
||||||
|
clientID string,
|
||||||
|
clientSecret *crypto.CryptoValue,
|
||||||
|
authMethodType domain.APIAuthMethodType,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if appID == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-XHsKt", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
if name = strings.TrimSpace(name); name == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-F7g21", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
if clientID == "" {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-XXED5", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
if exists, err := ExistsProject(ctx, filter, a.ID, a.ResourceOwner); !exists || err != nil {
|
||||||
|
return nil, errors.ThrowNotFound(err, "PROJE-Sf2gb", "Errors.Project.NotFound")
|
||||||
|
}
|
||||||
|
return []eventstore.Command{
|
||||||
|
project.NewApplicationAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&a.Aggregate,
|
||||||
|
appID,
|
||||||
|
name,
|
||||||
|
),
|
||||||
|
project.NewAPIConfigAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&a.Aggregate,
|
||||||
|
appID,
|
||||||
|
clientID,
|
||||||
|
clientSecret,
|
||||||
|
authMethodType,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExistsApp(ctx context.Context, filter preparation.FilterToQueryReducer, projectID, appID, resourceOwner string) (exists bool, err error) {
|
||||||
|
events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||||
|
ResourceOwner(resourceOwner).
|
||||||
|
OrderAsc().
|
||||||
|
AddQuery().
|
||||||
|
AggregateTypes(project.AggregateType).
|
||||||
|
AggregateIDs(projectID).
|
||||||
|
EventTypes(
|
||||||
|
project.ApplicationAddedType,
|
||||||
|
project.ApplicationRemovedType,
|
||||||
|
).Builder())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
switch e := event.(type) {
|
||||||
|
case *project.ApplicationAddedEvent:
|
||||||
|
if e.AppID == appID {
|
||||||
|
exists = true
|
||||||
|
}
|
||||||
|
case *project.ApplicationRemovedEvent:
|
||||||
|
if e.AppID == appID {
|
||||||
|
exists = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists, nil
|
||||||
|
}
|
386
internal/command/v2/project_app_test.go
Normal file
386
internal/command/v2/project_app_test.go
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddOIDCApp(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *project.Aggregate
|
||||||
|
appID string
|
||||||
|
name string
|
||||||
|
clientID string
|
||||||
|
filter preparation.FilterToQueryReducer
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
agg := project.NewAggregate("test", "test")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid appID",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "",
|
||||||
|
name: "name",
|
||||||
|
clientID: "clientID",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-NnavI", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid name",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "appID",
|
||||||
|
name: "",
|
||||||
|
clientID: "clientID",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-Fef31", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid clientID",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "appID",
|
||||||
|
name: "name",
|
||||||
|
clientID: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-ghTsJ", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project not exists",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "id",
|
||||||
|
name: "name",
|
||||||
|
clientID: "clientID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
CreateErr: errors.ThrowNotFound(nil, "PROJE-5LQ0U", "Errors.Project.NotFound"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "appID",
|
||||||
|
name: "name",
|
||||||
|
clientID: "clientID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewProjectAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&agg.Aggregate,
|
||||||
|
"project",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PrivateLabelingSettingUnspecified,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
project.NewApplicationAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
"appID",
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
project.NewOIDCConfigAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
"appID",
|
||||||
|
"clientID",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
domain.OIDCApplicationTypeWeb,
|
||||||
|
domain.OIDCAuthMethodTypeBasic,
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t,
|
||||||
|
AddOIDCApp(*tt.args.a,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
tt.args.appID,
|
||||||
|
tt.args.name,
|
||||||
|
tt.args.clientID,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
domain.OIDCApplicationTypeWeb,
|
||||||
|
domain.OIDCAuthMethodTypeBasic,
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
nil,
|
||||||
|
), tt.args.filter, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddAPIConfig(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *project.Aggregate
|
||||||
|
appID string
|
||||||
|
name string
|
||||||
|
clientID string
|
||||||
|
filter preparation.FilterToQueryReducer
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
agg := project.NewAggregate("test", "test")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid appID",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "",
|
||||||
|
name: "name",
|
||||||
|
clientID: "clientID",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-XHsKt", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid name",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "appID",
|
||||||
|
name: "",
|
||||||
|
clientID: "clientID",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-F7g21", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid clientID",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "appID",
|
||||||
|
name: "name",
|
||||||
|
clientID: "",
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-XXED5", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project not exists",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "id",
|
||||||
|
name: "name",
|
||||||
|
clientID: "clientID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
CreateErr: errors.ThrowNotFound(nil, "PROJE-Sf2gb", "Errors.Project.NotFound"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
appID: "appID",
|
||||||
|
name: "name",
|
||||||
|
clientID: "clientID",
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewProjectAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&agg.Aggregate,
|
||||||
|
"project",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PrivateLabelingSettingUnspecified,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
project.NewApplicationAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&agg.Aggregate,
|
||||||
|
"appID",
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
project.NewAPIConfigAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
"appID",
|
||||||
|
"clientID",
|
||||||
|
nil,
|
||||||
|
domain.APIAuthMethodTypeBasic,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t,
|
||||||
|
AddAPIApp(*tt.args.a,
|
||||||
|
tt.args.appID,
|
||||||
|
tt.args.name,
|
||||||
|
tt.args.clientID,
|
||||||
|
nil,
|
||||||
|
domain.APIAuthMethodTypeBasic,
|
||||||
|
), tt.args.filter, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExistsApp(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
filter preparation.FilterToQueryReducer
|
||||||
|
appID string
|
||||||
|
projectID string
|
||||||
|
resourceOwner string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantExists bool
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no events",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{}, nil
|
||||||
|
},
|
||||||
|
appID: "appID",
|
||||||
|
projectID: "projectID",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "app added",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewApplicationAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&project.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"appID",
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
appID: "appID",
|
||||||
|
projectID: "projectID",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: true,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "app removed",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewApplicationAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&project.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"appID",
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
project.NewApplicationRemovedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&project.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"appID",
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
appID: "appID",
|
||||||
|
projectID: "projectID",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error durring filter",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, errors.ThrowInternal(nil, "PROJE-Op26p", "Errors.Internal")
|
||||||
|
},
|
||||||
|
appID: "appID",
|
||||||
|
projectID: "projectID",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotExists, err := ExistsApp(context.Background(), tt.args.filter, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("ExistsUser() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotExists != tt.wantExists {
|
||||||
|
t.Errorf("ExistsUser() = %v, want %v", gotExists, tt.wantExists)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
195
internal/command/v2/project_test.go
Normal file
195
internal/command/v2/project_test.go
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddProject(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *project.Aggregate
|
||||||
|
name string
|
||||||
|
owner string
|
||||||
|
privateLabelingSetting domain.PrivateLabelingSetting
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
agg := project.NewAggregate("test", "test")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid name",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
name: "",
|
||||||
|
owner: "owner",
|
||||||
|
privateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-C01yo", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid private labeling setting",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
name: "name",
|
||||||
|
owner: "owner",
|
||||||
|
privateLabelingSetting: -1,
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "PROJE-AO52V", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid owner",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
name: "name",
|
||||||
|
owner: "",
|
||||||
|
privateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowPreconditionFailed(nil, "PROJE-hzxwo", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: agg,
|
||||||
|
name: "ZITADEL",
|
||||||
|
owner: "CAOS AG",
|
||||||
|
privateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
project.NewProjectAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
"ZITADEL",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
|
||||||
|
),
|
||||||
|
project.NewProjectMemberAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
"CAOS AG",
|
||||||
|
domain.RoleProjectOwner),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, AddProject(tt.args.a, tt.args.name, tt.args.owner, false, false, false, tt.args.privateLabelingSetting), nil, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExistsProject(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
filter preparation.FilterToQueryReducer
|
||||||
|
id string
|
||||||
|
resourceOwner string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantExists bool
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no events",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{}, nil
|
||||||
|
},
|
||||||
|
id: "id",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project added",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewProjectAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&project.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"name",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PrivateLabelingSettingEnforceProjectResourceOwnerPolicy,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
id: "id",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: true,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project removed",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewProjectAddedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&project.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"name",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PrivateLabelingSettingEnforceProjectResourceOwnerPolicy,
|
||||||
|
),
|
||||||
|
project.NewProjectRemovedEvent(
|
||||||
|
context.Background(),
|
||||||
|
&project.NewAggregate("id", "ro").Aggregate,
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
id: "id",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error durring filter",
|
||||||
|
args: args{
|
||||||
|
filter: func(_ context.Context, _ *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, errors.ThrowInternal(nil, "PROJE-Op26p", "Errors.Internal")
|
||||||
|
},
|
||||||
|
id: "id",
|
||||||
|
resourceOwner: "ro",
|
||||||
|
},
|
||||||
|
wantExists: false,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotExists, err := ExistsProject(context.Background(), tt.args.filter, tt.args.id, tt.args.resourceOwner)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("ExistsUser() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotExists != tt.wantExists {
|
||||||
|
t.Errorf("ExistsUser() = %v, want %v", gotExists, tt.wantExists)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
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