mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-12 11:04:25 +00:00
b8bec25129
* refactor(domain): add user type * fix(projections): start with login names * fix(login_policy): correct handling of user domain claimed event * fix(projections): add members * refactor: simplify member projections * add migration for members * add metadata to member projections * refactor: login name projection * fix: set correct suffixes on login name projections * test(projections): login name reduces * fix: correct cols in reduce member * test(projections): org, iam, project members * member additional cols and conds as opt, add project grant members * fix(migration): members * fix(migration): correct database name * migration version * migs * better naming for member cond and col * split project and project grant members * prepare member columns * feat(queries): membership query * test(queries): membership prepare * fix(queries): multiple projections for latest sequence * fix(api): use query for membership queries in auth and management * feat: org member queries * fix(api): use query for iam member calls * fix(queries): org members * fix(queries): project members * fix(queries): project grant members * refactor: remove unsued methods in repo-interfaces * start * fix(query): membership * fix(auth): list my project orgs * fix(query): member queries and user avatar column * refactor(auth): MyProjectOrgs * fix(queries): member and membership stmts * fix user test * fix(management): use query for project (-grant) members * fix(admin): use query for member calls * fix(api): add domain to org mapping * remove old idp * membership * refactor: remove old files * idp * refactor: use query for idps and idp user links * refactor(eventstore): rename EventPusher to Command, EventReader to Event, PushEvents to Push and FilterEvents to Filter * gloabl org check for org roles Co-authored-by: Livio Amstutz <livio.a@gmail.com>
1579 lines
33 KiB
Go
1579 lines
33 KiB
Go
package command
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"golang.org/x/text/language"
|
|
|
|
"github.com/caos/zitadel/internal/domain"
|
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
|
"github.com/caos/zitadel/internal/eventstore"
|
|
"github.com/caos/zitadel/internal/eventstore/repository"
|
|
"github.com/caos/zitadel/internal/id"
|
|
"github.com/caos/zitadel/internal/query"
|
|
"github.com/caos/zitadel/internal/repository/iam"
|
|
"github.com/caos/zitadel/internal/repository/member"
|
|
"github.com/caos/zitadel/internal/repository/org"
|
|
"github.com/caos/zitadel/internal/repository/project"
|
|
"github.com/caos/zitadel/internal/repository/user"
|
|
)
|
|
|
|
func TestCommandSide_UsernameChange(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
userID string
|
|
username string
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
username: "username",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "orgid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "",
|
|
userID: "user1",
|
|
username: "username",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "username missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
username: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user removed, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
username: "username",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "username not changed, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
username: "username",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "org iam policy not found, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
username: "username",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "invalid username, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectFilter(),
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
iam.NewOrgIAMPolicyAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
username: "test@test.ch",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "change username, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectFilter(),
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
iam.NewOrgIAMPolicyAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUsernameChangedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"username1",
|
|
true,
|
|
),
|
|
),
|
|
},
|
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
|
|
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username1", "org1", true)),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
username: "username1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := r.ChangeUsername(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.username)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_DeactivateUser(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
userID string
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "user already inactive, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
user.NewUserDeactivatedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "deactivate user, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserDeactivatedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := r.DeactivateUser(tt.args.ctx, tt.args.userID, tt.args.orgID)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_ReactivateUser(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
userID string
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "user already active, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "reactivate user, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
user.NewUserDeactivatedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserReactivatedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := r.ReactivateUser(tt.args.ctx, tt.args.userID, tt.args.orgID)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_LockUser(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
userID string
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "user already locked, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
user.NewUserLockedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "lock user, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserLockedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := r.LockUser(tt.args.ctx, tt.args.userID, tt.args.orgID)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_UnlockUser(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
userID string
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "user already active, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "unlock user, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
user.NewUserLockedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserUnlockedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := r.UnlockUser(tt.args.ctx, tt.args.userID, tt.args.orgID)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_RemoveUser(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
userID string
|
|
cascadeUserMemberships []*query.Membership
|
|
cascadeUserGrants []string
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "org iam policy not found, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectFilter(),
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsPreconditionFailed,
|
|
},
|
|
},
|
|
{
|
|
name: "remove user, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectFilter(),
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
iam.NewOrgIAMPolicyAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserRemovedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
nil,
|
|
true,
|
|
),
|
|
),
|
|
},
|
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "remove user with erxternal idp, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"idpConfigID",
|
|
"displayName",
|
|
"externalUserID",
|
|
),
|
|
),
|
|
),
|
|
expectFilter(),
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
iam.NewOrgIAMPolicyAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserRemovedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
nil,
|
|
true,
|
|
),
|
|
),
|
|
},
|
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
|
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("idpConfigID", "externalUserID")),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "remove user with user memberships, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectFilter(),
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
iam.NewOrgIAMPolicyAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewUserRemovedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
nil,
|
|
true,
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
iam.NewMemberCascadeRemovedEvent(context.Background(),
|
|
&iam.NewAggregate().Aggregate,
|
|
"user1",
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
org.NewMemberCascadeRemovedEvent(context.Background(),
|
|
&org.NewAggregate("org1", "org1").Aggregate,
|
|
"user1",
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
project.NewProjectMemberCascadeRemovedEvent(context.Background(),
|
|
&project.NewAggregate("project1", "org1").Aggregate,
|
|
"user1",
|
|
),
|
|
),
|
|
eventFromEventPusher(
|
|
project.NewProjectGrantMemberCascadeRemovedEvent(context.Background(),
|
|
&project.NewAggregate("project1", "org1").Aggregate,
|
|
"user1",
|
|
"grant1",
|
|
),
|
|
),
|
|
},
|
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
|
|
uniqueConstraintsFromEventConstraint(member.NewRemoveMemberUniqueConstraint(domain.IAMID, "user1")),
|
|
uniqueConstraintsFromEventConstraint(member.NewRemoveMemberUniqueConstraint("org1", "user1")),
|
|
uniqueConstraintsFromEventConstraint(member.NewRemoveMemberUniqueConstraint("project1", "user1")),
|
|
uniqueConstraintsFromEventConstraint(project.NewRemoveProjectGrantMemberUniqueConstraint("project1", "user1", "grant1")),
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
cascadeUserMemberships: []*query.Membership{
|
|
{
|
|
IAM: &query.IAMMembership{
|
|
IAMID: "IAM",
|
|
},
|
|
UserID: "user1",
|
|
ResourceOwner: "org1",
|
|
},
|
|
{
|
|
Org: &query.OrgMembership{
|
|
OrgID: "org1",
|
|
},
|
|
UserID: "user1",
|
|
ResourceOwner: "org1",
|
|
},
|
|
{
|
|
|
|
Project: &query.ProjectMembership{
|
|
ProjectID: "project1",
|
|
},
|
|
UserID: "user1",
|
|
ResourceOwner: "org1",
|
|
},
|
|
{
|
|
ProjectGrant: &query.ProjectGrantMembership{
|
|
ProjectID: "project1",
|
|
GrantID: "grant1",
|
|
},
|
|
UserID: "user1",
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
res: res{
|
|
want: &domain.ObjectDetails{
|
|
ResourceOwner: "org1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := r.RemoveUser(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.cascadeUserMemberships, tt.args.cascadeUserGrants...)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_AddUserToken(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
idGenerator id.Generator
|
|
}
|
|
type (
|
|
args struct {
|
|
ctx context.Context
|
|
orgID string
|
|
agentID string
|
|
clientID string
|
|
userID string
|
|
audience []string
|
|
scopes []string
|
|
lifetime time.Duration
|
|
}
|
|
)
|
|
type res struct {
|
|
want *domain.Token
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, not found error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
orgID: "org1",
|
|
userID: "user1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
idGenerator: tt.fields.idGenerator,
|
|
}
|
|
got, err := r.AddUserToken(tt.args.ctx, tt.args.orgID, tt.args.agentID, tt.args.clientID, tt.args.userID, tt.args.audience, tt.args.scopes, tt.args.lifetime)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommands_RevokeAccessToken(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type args struct {
|
|
ctx context.Context
|
|
userID string
|
|
orgID string
|
|
tokenID string
|
|
}
|
|
type res struct {
|
|
want *domain.ObjectDetails
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
"id missing error",
|
|
fields{
|
|
eventstoreExpect(t),
|
|
},
|
|
args{
|
|
context.Background(),
|
|
"userID",
|
|
"orgID",
|
|
"",
|
|
},
|
|
res{
|
|
nil,
|
|
caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
"not active error",
|
|
fields{
|
|
eventstoreExpect(t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewUserTokenAddedEvent(context.Background(),
|
|
&user.NewAggregate("userID", "orgID").Aggregate,
|
|
"tokenID",
|
|
"clientID",
|
|
"agentID",
|
|
"de",
|
|
"refreshTokenID",
|
|
[]string{"clientID"},
|
|
[]string{"openid"},
|
|
time.Now(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args{
|
|
context.Background(),
|
|
"userID",
|
|
"orgID",
|
|
"tokenID",
|
|
},
|
|
res{
|
|
nil,
|
|
caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
"active ok",
|
|
fields{
|
|
eventstoreExpect(t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewUserTokenAddedEvent(context.Background(),
|
|
&user.NewAggregate("userID", "orgID").Aggregate,
|
|
"tokenID",
|
|
"clientID",
|
|
"agentID",
|
|
"de",
|
|
"refreshTokenID",
|
|
[]string{"clientID"},
|
|
[]string{"openid"},
|
|
time.Now().Add(5*time.Hour),
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
eventPusherToEvents(
|
|
user.NewUserTokenRemovedEvent(context.Background(),
|
|
&user.NewAggregate("userID", "orgID").Aggregate,
|
|
"tokenID",
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
args{
|
|
context.Background(),
|
|
"userID",
|
|
"orgID",
|
|
"tokenID",
|
|
},
|
|
res{
|
|
&domain.ObjectDetails{
|
|
ResourceOwner: "orgID",
|
|
},
|
|
nil,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
got, err := c.RevokeAccessToken(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.tokenID)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
if tt.res.err == nil {
|
|
assert.Equal(t, tt.res.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCommandSide_UserDomainClaimedSent(t *testing.T) {
|
|
type fields struct {
|
|
eventstore *eventstore.Eventstore
|
|
}
|
|
type args struct {
|
|
ctx context.Context
|
|
userID string
|
|
resourceOwner string
|
|
}
|
|
type res struct {
|
|
err func(error) bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
res res
|
|
}{
|
|
{
|
|
name: "userid missing, invalid argument error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
resourceOwner: "org1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsErrorInvalidArgument,
|
|
},
|
|
},
|
|
{
|
|
name: "user not existing, precondition error",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
userID: "user1",
|
|
resourceOwner: "org1",
|
|
},
|
|
res: res{
|
|
err: caos_errs.IsNotFound,
|
|
},
|
|
},
|
|
{
|
|
name: "code sent, ok",
|
|
fields: fields{
|
|
eventstore: eventstoreExpect(
|
|
t,
|
|
expectFilter(
|
|
eventFromEventPusher(
|
|
user.NewHumanAddedEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
"username",
|
|
"firstname",
|
|
"lastname",
|
|
"nickname",
|
|
"displayname",
|
|
language.German,
|
|
domain.GenderUnspecified,
|
|
"email@test.ch",
|
|
true,
|
|
),
|
|
),
|
|
),
|
|
expectPush(
|
|
[]*repository.Event{
|
|
eventFromEventPusher(
|
|
user.NewDomainClaimedSentEvent(context.Background(),
|
|
&user.NewAggregate("user1", "org1").Aggregate,
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
},
|
|
args: args{
|
|
ctx: context.Background(),
|
|
userID: "user1",
|
|
resourceOwner: "org1",
|
|
},
|
|
res: res{},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := &Commands{
|
|
eventstore: tt.fields.eventstore,
|
|
}
|
|
err := r.UserDomainClaimedSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID)
|
|
if tt.res.err == nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
if tt.res.err != nil && !tt.res.err(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
})
|
|
}
|
|
}
|