mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:57:32 +00:00
feat(api): add organisation service (#6340)
* setup org with multiple admins * tests * add missing proto * remove machine users (for now) * update tests with idp case * fix package * organisation -> organization * fix test
This commit is contained in:
@@ -38,7 +38,7 @@ type InstanceSetup struct {
|
||||
InstanceName string
|
||||
CustomDomain string
|
||||
DefaultLanguage language.Tag
|
||||
Org OrgSetup
|
||||
Org InstanceOrgSetup
|
||||
SecretGenerators struct {
|
||||
PasswordSaltCost uint
|
||||
ClientSecret *crypto.GeneratorConfig
|
||||
|
@@ -14,7 +14,10 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
type OrgSetup struct {
|
||||
// InstanceOrgSetup is used for the first organisation in the instance setup.
|
||||
// It used to be called OrgSetup, which now allows multiple Users, but it's used in the config.yaml and therefore
|
||||
// a breaking change was not possible.
|
||||
type InstanceOrgSetup struct {
|
||||
Name string
|
||||
CustomDomain string
|
||||
Human *AddHuman
|
||||
@@ -22,83 +25,210 @@ type OrgSetup struct {
|
||||
Roles []string
|
||||
}
|
||||
|
||||
func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID string, userIDs ...string) (userID string, token string, machineKey *MachineKey, details *domain.ObjectDetails, err error) {
|
||||
userID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
type OrgSetup struct {
|
||||
Name string
|
||||
CustomDomain string
|
||||
Admins []*OrgSetupAdmin
|
||||
}
|
||||
|
||||
// OrgSetupAdmin describes a user to be created (Human / Machine) or an existing (ID) to be used for an org setup.
|
||||
type OrgSetupAdmin struct {
|
||||
ID string
|
||||
Human *AddHuman
|
||||
Machine *AddMachine
|
||||
Roles []string
|
||||
}
|
||||
|
||||
type orgSetupCommands struct {
|
||||
validations []preparation.Validation
|
||||
aggregate *org.Aggregate
|
||||
commands *Commands
|
||||
|
||||
admins []*OrgSetupAdmin
|
||||
pats []*PersonalAccessToken
|
||||
machineKeys []*MachineKey
|
||||
}
|
||||
|
||||
type CreatedOrg struct {
|
||||
ObjectDetails *domain.ObjectDetails
|
||||
CreatedAdmins []*CreatedOrgAdmin
|
||||
}
|
||||
|
||||
type CreatedOrgAdmin struct {
|
||||
ID string
|
||||
EmailCode *string
|
||||
PhoneCode *string
|
||||
PAT *PersonalAccessToken
|
||||
MachineKey *MachineKey
|
||||
}
|
||||
|
||||
func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID string, allowInitialMail bool, userIDs ...string) (_ *CreatedOrg, err error) {
|
||||
cmds := c.newOrgSetupCommands(ctx, orgID, o, userIDs)
|
||||
for _, admin := range o.Admins {
|
||||
if err = cmds.setupOrgAdmin(admin, allowInitialMail); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = cmds.addCustomDomain(o.CustomDomain, userIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cmds.push(ctx)
|
||||
}
|
||||
|
||||
func (c *Commands) newOrgSetupCommands(ctx context.Context, orgID string, orgSetup *OrgSetup, userIDs []string) *orgSetupCommands {
|
||||
orgAgg := org.NewAggregate(orgID)
|
||||
userAgg := user.NewAggregate(userID, orgID)
|
||||
|
||||
roles := []string{domain.RoleOrgOwner}
|
||||
if len(o.Roles) > 0 {
|
||||
roles = o.Roles
|
||||
}
|
||||
|
||||
validations := []preparation.Validation{
|
||||
AddOrgCommand(ctx, orgAgg, o.Name, userIDs...),
|
||||
AddOrgCommand(ctx, orgAgg, orgSetup.Name, userIDs...),
|
||||
}
|
||||
return &orgSetupCommands{
|
||||
validations: validations,
|
||||
aggregate: orgAgg,
|
||||
commands: c,
|
||||
admins: orgSetup.Admins,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *orgSetupCommands) setupOrgAdmin(admin *OrgSetupAdmin, allowInitialMail bool) error {
|
||||
if admin.ID != "" {
|
||||
c.validations = append(c.validations, c.commands.AddOrgMemberCommand(c.aggregate, admin.ID, orgAdminRoles(admin.Roles)...))
|
||||
return nil
|
||||
}
|
||||
userID, err := c.commands.idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if admin.Human != nil {
|
||||
admin.Human.ID = userID
|
||||
c.validations = append(c.validations, c.commands.AddHumanCommand(admin.Human, c.aggregate.ID, c.commands.userPasswordHasher, c.commands.userEncryption, allowInitialMail))
|
||||
} else if admin.Machine != nil {
|
||||
admin.Machine.Machine.AggregateID = userID
|
||||
if err = c.setupOrgAdminMachine(c.aggregate, admin.Machine); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.validations = append(c.validations, c.commands.AddOrgMemberCommand(c.aggregate, userID, orgAdminRoles(admin.Roles)...))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *orgSetupCommands) setupOrgAdminMachine(orgAgg *org.Aggregate, machine *AddMachine) error {
|
||||
userAgg := user.NewAggregate(machine.Machine.AggregateID, orgAgg.ID)
|
||||
c.validations = append(c.validations, AddMachineCommand(userAgg, machine.Machine))
|
||||
var pat *PersonalAccessToken
|
||||
if o.Human != nil {
|
||||
o.Human.ID = userID
|
||||
validations = append(validations, c.AddHumanCommand(o.Human, orgID, c.userPasswordHasher, c.userEncryption, true))
|
||||
} else if o.Machine != nil {
|
||||
validations = append(validations, AddMachineCommand(userAgg, o.Machine.Machine))
|
||||
if o.Machine.Pat != nil {
|
||||
pat = NewPersonalAccessToken(orgID, userID, o.Machine.Pat.ExpirationDate, o.Machine.Pat.Scopes, domain.UserTypeMachine)
|
||||
tokenID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
pat.TokenID = tokenID
|
||||
validations = append(validations, prepareAddPersonalAccessToken(pat, c.keyAlgorithm))
|
||||
var machineKey *MachineKey
|
||||
if machine.Pat != nil {
|
||||
pat = NewPersonalAccessToken(orgAgg.ID, machine.Machine.AggregateID, machine.Pat.ExpirationDate, machine.Pat.Scopes, domain.UserTypeMachine)
|
||||
tokenID, err := c.commands.idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if o.Machine.MachineKey != nil {
|
||||
machineKey = NewMachineKey(orgID, userID, o.Machine.MachineKey.ExpirationDate, o.Machine.MachineKey.Type)
|
||||
keyID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
machineKey.KeyID = keyID
|
||||
validations = append(validations, prepareAddUserMachineKey(machineKey, c.keySize))
|
||||
pat.TokenID = tokenID
|
||||
c.pats = append(c.pats, pat)
|
||||
c.validations = append(c.validations, prepareAddPersonalAccessToken(pat, c.commands.keyAlgorithm))
|
||||
}
|
||||
if machine.MachineKey != nil {
|
||||
machineKey = NewMachineKey(orgAgg.ID, machine.Machine.AggregateID, machine.MachineKey.ExpirationDate, machine.MachineKey.Type)
|
||||
keyID, err := c.commands.idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
machineKey.KeyID = keyID
|
||||
c.machineKeys = append(c.machineKeys, machineKey)
|
||||
c.validations = append(c.validations, prepareAddUserMachineKey(machineKey, c.commands.keySize))
|
||||
}
|
||||
validations = append(validations, c.AddOrgMemberCommand(orgAgg, userID, roles...))
|
||||
return nil
|
||||
}
|
||||
|
||||
if o.CustomDomain != "" {
|
||||
validations = append(validations, c.prepareAddOrgDomain(orgAgg, o.CustomDomain, userIDs))
|
||||
func (c *orgSetupCommands) addCustomDomain(domain string, userIDs []string) error {
|
||||
if domain != "" {
|
||||
c.validations = append(c.validations, c.commands.prepareAddOrgDomain(c.aggregate, domain, userIDs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validations...)
|
||||
func orgAdminRoles(roles []string) []string {
|
||||
if len(roles) > 0 {
|
||||
return roles
|
||||
}
|
||||
return []string{domain.RoleOrgOwner}
|
||||
}
|
||||
|
||||
func (c *orgSetupCommands) push(ctx context.Context) (_ *CreatedOrg, err error) {
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.commands.eventstore.Filter, c.validations...)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
events, err := c.eventstore.Push(ctx, cmds...)
|
||||
events, err := c.commands.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pat != nil {
|
||||
token = pat.Token
|
||||
}
|
||||
|
||||
return userID, token, machineKey, &domain.ObjectDetails{
|
||||
Sequence: events[len(events)-1].Sequence(),
|
||||
EventDate: events[len(events)-1].CreationDate(),
|
||||
ResourceOwner: orgID,
|
||||
return &CreatedOrg{
|
||||
ObjectDetails: &domain.ObjectDetails{
|
||||
Sequence: events[len(events)-1].Sequence(),
|
||||
EventDate: events[len(events)-1].CreationDate(),
|
||||
ResourceOwner: c.aggregate.ID,
|
||||
},
|
||||
CreatedAdmins: c.createdAdmins(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, userIDs ...string) (string, *domain.ObjectDetails, error) {
|
||||
func (c *orgSetupCommands) createdAdmins() []*CreatedOrgAdmin {
|
||||
users := make([]*CreatedOrgAdmin, 0, len(c.admins))
|
||||
for _, admin := range c.admins {
|
||||
if admin.ID != "" {
|
||||
continue
|
||||
}
|
||||
if admin.Human != nil {
|
||||
users = append(users, c.createdHumanAdmin(admin))
|
||||
continue
|
||||
}
|
||||
if admin.Machine != nil {
|
||||
users = append(users, c.createdMachineAdmin(admin))
|
||||
}
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
func (c *orgSetupCommands) createdHumanAdmin(admin *OrgSetupAdmin) *CreatedOrgAdmin {
|
||||
createdAdmin := &CreatedOrgAdmin{
|
||||
ID: admin.Human.ID,
|
||||
}
|
||||
if admin.Human.EmailCode != nil {
|
||||
createdAdmin.EmailCode = admin.Human.EmailCode
|
||||
}
|
||||
return createdAdmin
|
||||
}
|
||||
|
||||
func (c *orgSetupCommands) createdMachineAdmin(admin *OrgSetupAdmin) *CreatedOrgAdmin {
|
||||
createdAdmin := &CreatedOrgAdmin{
|
||||
ID: admin.Machine.Machine.AggregateID,
|
||||
}
|
||||
if admin.Machine.Pat != nil {
|
||||
for _, pat := range c.pats {
|
||||
if pat.AggregateID == createdAdmin.ID {
|
||||
createdAdmin.PAT = pat
|
||||
}
|
||||
}
|
||||
}
|
||||
if admin.Machine.MachineKey != nil {
|
||||
for _, key := range c.machineKeys {
|
||||
if key.AggregateID == createdAdmin.ID {
|
||||
createdAdmin.MachineKey = key
|
||||
}
|
||||
}
|
||||
}
|
||||
return createdAdmin
|
||||
}
|
||||
|
||||
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail bool, userIDs ...string) (*CreatedOrg, error) {
|
||||
orgID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userID, _, _, details, err := c.setUpOrgWithIDs(ctx, o, orgID, userIDs...)
|
||||
return userID, details, err
|
||||
return c.setUpOrgWithIDs(ctx, o, orgID, allowInitialMail, userIDs...)
|
||||
}
|
||||
|
||||
// AddOrgCommand defines the commands to create a new org,
|
||||
|
@@ -3,11 +3,15 @@ package command
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
openid "github.com/zitadel/oidc/v2/pkg/oidc"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -1325,3 +1329,450 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
newCode cryptoCodeFunc
|
||||
keyAlgorithm crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
setupOrg *OrgSetup
|
||||
allowInitialMail bool
|
||||
userIDs []string
|
||||
}
|
||||
type res struct {
|
||||
createdOrg *CreatedOrg
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "org name empty, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: errors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "userID not existing, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
{
|
||||
ID: "userID",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: errors.ThrowPreconditionFailed(nil, "ORG-GoXOn", "Errors.User.NotFound"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "human invalid, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
{
|
||||
Human: &AddHuman{
|
||||
Username: "",
|
||||
FirstName: "firstname",
|
||||
LastName: "lastname",
|
||||
Email: Email{
|
||||
Address: "email@test.ch",
|
||||
Verified: true,
|
||||
},
|
||||
PreferredLanguage: language.English,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
allowInitialMail: true,
|
||||
},
|
||||
res: res{
|
||||
err: errors.ThrowInvalidArgument(nil, "V2-zzad3", "Errors.Invalid.Argument"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "human added with initial mail",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(), // add human exists check
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(), // org member check
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"",
|
||||
"firstname lastname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(org.NewOrgAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"Org",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate, "org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"",
|
||||
"firstname lastname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanEmailVerifiedEvent(context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanInitialCodeAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("userinit"),
|
||||
},
|
||||
1*time.Hour,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(org.NewMemberAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"userID",
|
||||
domain.RoleOrgOwner,
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(org.NewAddOrgNameUniqueConstraint("Org")),
|
||||
uniqueConstraintsFromEventConstraint(org.NewAddOrgDomainUniqueConstraint("org.iam-domain")),
|
||||
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "orgID", true)),
|
||||
uniqueConstraintsFromEventConstraint(member.NewAddMemberUniqueConstraint("orgID", "userID")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"),
|
||||
newCode: mockCode("userinit", time.Hour),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
{
|
||||
Human: &AddHuman{
|
||||
Username: "username",
|
||||
FirstName: "firstname",
|
||||
LastName: "lastname",
|
||||
Email: Email{
|
||||
Address: "email@test.ch",
|
||||
Verified: true,
|
||||
},
|
||||
PreferredLanguage: language.English,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
allowInitialMail: true,
|
||||
},
|
||||
res: res{
|
||||
createdOrg: &CreatedOrg{
|
||||
ObjectDetails: &domain.ObjectDetails{
|
||||
ResourceOwner: "orgID",
|
||||
},
|
||||
CreatedAdmins: []*CreatedOrgAdmin{
|
||||
{
|
||||
ID: "userID",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing human added",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"",
|
||||
"firstname lastname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(), // org member check
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(org.NewOrgAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"Org",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate, "org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewMemberAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"userID",
|
||||
domain.RoleOrgOwner,
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(org.NewAddOrgNameUniqueConstraint("Org")),
|
||||
uniqueConstraintsFromEventConstraint(org.NewAddOrgDomainUniqueConstraint("org.iam-domain")),
|
||||
uniqueConstraintsFromEventConstraint(member.NewAddMemberUniqueConstraint("orgID", "userID")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
{
|
||||
ID: "userID",
|
||||
},
|
||||
},
|
||||
},
|
||||
allowInitialMail: true,
|
||||
},
|
||||
res: res{
|
||||
createdOrg: &CreatedOrg{
|
||||
ObjectDetails: &domain.ObjectDetails{
|
||||
ResourceOwner: "orgID",
|
||||
},
|
||||
CreatedAdmins: []*CreatedOrgAdmin{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "machine added with pat",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(), // add machine exists check
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectFilter(),
|
||||
expectFilter(), // org member check
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"",
|
||||
"firstname lastname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(org.NewOrgAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"Org",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate, "org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"org.iam-domain",
|
||||
)),
|
||||
eventFromEventPusher(
|
||||
user.NewMachineAddedEvent(context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"name",
|
||||
"description",
|
||||
true,
|
||||
domain.OIDCTokenTypeBearer,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewPersonalAccessTokenAddedEvent(context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"tokenID",
|
||||
testNow.Add(time.Hour),
|
||||
[]string{openid.ScopeOpenID},
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(org.NewMemberAddedEvent(context.Background(),
|
||||
&org.NewAggregate("orgID").Aggregate,
|
||||
"userID",
|
||||
domain.RoleOrgOwner,
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(org.NewAddOrgNameUniqueConstraint("Org")),
|
||||
uniqueConstraintsFromEventConstraint(org.NewAddOrgDomainUniqueConstraint("org.iam-domain")),
|
||||
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "orgID", true)),
|
||||
uniqueConstraintsFromEventConstraint(member.NewAddMemberUniqueConstraint("orgID", "userID")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID", "tokenID"),
|
||||
newCode: mockCode("userinit", time.Hour),
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
{
|
||||
Machine: &AddMachine{
|
||||
Machine: &Machine{
|
||||
Username: "username",
|
||||
Name: "name",
|
||||
Description: "description",
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
},
|
||||
Pat: &AddPat{
|
||||
ExpirationDate: testNow.Add(time.Hour),
|
||||
Scopes: []string{openid.ScopeOpenID},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
createdOrg: &CreatedOrg{
|
||||
ObjectDetails: &domain.ObjectDetails{
|
||||
ResourceOwner: "orgID",
|
||||
},
|
||||
CreatedAdmins: []*CreatedOrgAdmin{
|
||||
{
|
||||
ID: "userID",
|
||||
PAT: &PersonalAccessToken{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "userID",
|
||||
ResourceOwner: "orgID",
|
||||
},
|
||||
ExpirationDate: testNow.Add(time.Hour),
|
||||
Scopes: []string{openid.ScopeOpenID},
|
||||
AllowedUserType: domain.UserTypeMachine,
|
||||
TokenID: "tokenID",
|
||||
Token: "dG9rZW5JRDp1c2VySUQ", // token
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
newCode: tt.fields.newCode,
|
||||
keyAlgorithm: tt.fields.keyAlgorithm,
|
||||
zitadelRoles: []authz.RoleMapping{
|
||||
{
|
||||
Role: domain.RoleOrgOwner,
|
||||
},
|
||||
},
|
||||
}
|
||||
got, err := r.SetUpOrg(tt.args.ctx, tt.args.setupOrg, tt.args.allowInitialMail, tt.args.userIDs...)
|
||||
assert.ErrorIs(t, err, tt.res.err)
|
||||
assert.Equal(t, tt.res.createdOrg, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user