mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:57:33 +00:00
feat: add management for ldap idp template (#5220)
Add management functionality for LDAP idps with templates and the basic functionality for the LDAP provider, which can then be used with a separate login page in the future. --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
17
internal/command/idp.go
Normal file
17
internal/command/idp.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package command
|
||||
|
||||
import "github.com/zitadel/zitadel/internal/repository/idp"
|
||||
|
||||
type LDAPProvider struct {
|
||||
Name string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password string
|
||||
LDAPAttributes idp.LDAPAttributes
|
||||
IDPOptions idp.Options
|
||||
}
|
208
internal/command/idp_model.go
Normal file
208
internal/command/idp_model.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
)
|
||||
|
||||
type LDAPIDPWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
ID string
|
||||
Name string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password *crypto.CryptoValue
|
||||
idp.LDAPAttributes
|
||||
idp.Options
|
||||
|
||||
State domain.IDPState
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *idp.LDAPIDPAddedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.reduceAddeddEvent(e)
|
||||
case *idp.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.reduceChangedEvent(e)
|
||||
case *idp.RemovedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.IDPStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) reduceAddeddEvent(e *idp.LDAPIDPAddedEvent) {
|
||||
wm.Name = e.Name
|
||||
wm.Host = e.Host
|
||||
wm.Port = e.Port
|
||||
wm.TLS = e.TLS
|
||||
wm.BaseDN = e.BaseDN
|
||||
wm.UserObjectClass = e.UserObjectClass
|
||||
wm.UserUniqueAttribute = e.UserUniqueAttribute
|
||||
wm.Admin = e.Admin
|
||||
wm.Password = e.Password
|
||||
wm.LDAPAttributes = e.LDAPAttributes
|
||||
wm.Options = e.Options
|
||||
wm.State = domain.IDPStateActive
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) reduceChangedEvent(e *idp.LDAPIDPChangedEvent) {
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.Host != nil {
|
||||
wm.Host = *e.Host
|
||||
}
|
||||
if e.Port != nil {
|
||||
wm.Port = *e.Port
|
||||
}
|
||||
if e.TLS != nil {
|
||||
wm.TLS = *e.TLS
|
||||
}
|
||||
if e.BaseDN != nil {
|
||||
wm.BaseDN = *e.BaseDN
|
||||
}
|
||||
if e.UserObjectClass != nil {
|
||||
wm.UserObjectClass = *e.UserObjectClass
|
||||
}
|
||||
if e.UserUniqueAttribute != nil {
|
||||
wm.UserUniqueAttribute = *e.UserUniqueAttribute
|
||||
}
|
||||
if e.Admin != nil {
|
||||
wm.Admin = *e.Admin
|
||||
}
|
||||
if e.Password != nil {
|
||||
wm.Password = e.Password
|
||||
}
|
||||
wm.LDAPAttributes.ReduceChanges(e.LDAPAttributeChanges)
|
||||
wm.Options.ReduceChanges(e.OptionChanges)
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) NewChanges(
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) ([]idp.LDAPIDPChanges, error) {
|
||||
changes := make([]idp.LDAPIDPChanges, 0)
|
||||
var cryptedPassword *crypto.CryptoValue
|
||||
var err error
|
||||
if password != "" {
|
||||
cryptedPassword, err = crypto.Crypt([]byte(password), secretCrypto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes = append(changes, idp.ChangeLDAPPassword(cryptedPassword))
|
||||
}
|
||||
if wm.Name != name {
|
||||
changes = append(changes, idp.ChangeLDAPName(name))
|
||||
}
|
||||
if wm.Host != host {
|
||||
changes = append(changes, idp.ChangeLDAPHost(host))
|
||||
}
|
||||
if wm.Port != port {
|
||||
changes = append(changes, idp.ChangeLDAPPort(port))
|
||||
}
|
||||
if wm.TLS != tls {
|
||||
changes = append(changes, idp.ChangeLDAPTLS(tls))
|
||||
}
|
||||
if wm.BaseDN != baseDN {
|
||||
changes = append(changes, idp.ChangeLDAPBaseDN(baseDN))
|
||||
}
|
||||
if wm.UserObjectClass != userObjectClass {
|
||||
changes = append(changes, idp.ChangeLDAPUserObjectClass(userObjectClass))
|
||||
}
|
||||
if wm.UserUniqueAttribute != userUniqueAttribute {
|
||||
changes = append(changes, idp.ChangeLDAPUserUniqueAttribute(userUniqueAttribute))
|
||||
}
|
||||
if wm.Admin != admin {
|
||||
changes = append(changes, idp.ChangeLDAPAdmin(admin))
|
||||
}
|
||||
attrs := wm.LDAPAttributes.Changes(attributes)
|
||||
if !attrs.IsZero() {
|
||||
changes = append(changes, idp.ChangeLDAPAttributes(attrs))
|
||||
}
|
||||
opts := wm.Options.Changes(options)
|
||||
if !opts.IsZero() {
|
||||
changes = append(changes, idp.ChangeLDAPOptions(opts))
|
||||
}
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
type IDPRemoveWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
ID string
|
||||
State domain.IDPState
|
||||
name string
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *idp.LDAPIDPAddedEvent:
|
||||
wm.reduceAdded(e.ID, e.Name)
|
||||
case *idp.LDAPIDPChangedEvent:
|
||||
wm.reduceChanged(e.ID, e.Name)
|
||||
case *idp.RemovedEvent:
|
||||
wm.reduceRemoved(e.ID)
|
||||
case *idpconfig.IDPConfigAddedEvent:
|
||||
wm.reduceAdded(e.ConfigID, "")
|
||||
case *idpconfig.IDPConfigRemovedEvent:
|
||||
wm.reduceRemoved(e.ConfigID)
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) reduceAdded(id string, name string) {
|
||||
if wm.ID != id {
|
||||
return
|
||||
}
|
||||
wm.State = domain.IDPStateActive
|
||||
wm.name = name
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) reduceChanged(id string, name *string) {
|
||||
if wm.ID != id || name == nil {
|
||||
return
|
||||
}
|
||||
wm.name = *name
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) reduceRemoved(id string) {
|
||||
if wm.ID != id {
|
||||
return
|
||||
}
|
||||
wm.State = domain.IDPStateRemoved
|
||||
}
|
205
internal/command/instance_idp.go
Normal file
205
internal/command/instance_idp.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
func (c *Commands) AddInstanceLDAPProvider(ctx context.Context, provider LDAPProvider) (string, *domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
id, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddInstanceLDAPProvider(instanceAgg, id, provider))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return id, pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateInstanceLDAPProvider(ctx context.Context, id string, provider LDAPProvider) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareUpdateInstanceLDAPProvider(instanceAgg, id, provider))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cmds) == 0 {
|
||||
// no change, so return directly
|
||||
return &domain.ObjectDetails{}, nil
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeleteInstanceProvider(ctx context.Context, id string) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareDeleteInstanceProvider(instanceAgg, id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddInstanceLDAPProvider(a *instance.Aggregate, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAfdd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SDVg2", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sv31s", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdgf4", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-AEG2w", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAD5n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Password = strings.TrimSpace(provider.Password); provider.Password == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdf5h", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPInstanceIDPWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.Password), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{
|
||||
instance.NewLDAPIDPAddedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
secret,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareUpdateInstanceLDAPProvider(a *instance.Aggregate, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if id = strings.TrimSpace(id); id == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Dgdbs", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Sffgd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Dz62d", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-vb3ss", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-hbere", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-ASFt6", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-DG45z", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPInstanceIDPWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "INST-ASF3F", "Errors.Instance.IDPConfig.NotExisting")
|
||||
}
|
||||
event, err := writeModel.NewChangedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
writeModel.Name,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.Password,
|
||||
c.idpConfigEncryption,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return []eventstore.Command{event}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareDeleteInstanceProvider(a *instance.Aggregate, id string) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewInstanceIDPRemoveWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "INST-Se3tg", "Errors.Instance.IDPConfig.NotExisting")
|
||||
}
|
||||
return []eventstore.Command{instance.NewIDPRemovedEvent(ctx, &a.Aggregate, id, writeModel.name)}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
163
internal/command/instance_idp_model.go
Normal file
163
internal/command/instance_idp_model.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
type InstanceLDAPIDPWriteModel struct {
|
||||
LDAPIDPWriteModel
|
||||
}
|
||||
|
||||
func NewLDAPInstanceIDPWriteModel(instanceID, id string) *InstanceLDAPIDPWriteModel {
|
||||
return &InstanceLDAPIDPWriteModel{
|
||||
LDAPIDPWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: instanceID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) Reduce() error {
|
||||
return wm.LDAPIDPWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *instance.LDAPIDPAddedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *instance.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *instance.IDPRemovedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.LDAPIDPWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.LDAPIDPAddedEventType,
|
||||
instance.LDAPIDPChangedEventType,
|
||||
instance.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) (*instance.LDAPIDPChangedEvent, error) {
|
||||
|
||||
changes, err := wm.LDAPIDPWriteModel.NewChanges(
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
secretCrypto,
|
||||
attributes,
|
||||
options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
changeEvent, err := instance.NewLDAPIDPChangedEvent(ctx, aggregate, id, oldName, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type InstanceIDPRemoveWriteModel struct {
|
||||
IDPRemoveWriteModel
|
||||
}
|
||||
|
||||
func NewInstanceIDPRemoveWriteModel(instanceID, id string) *InstanceIDPRemoveWriteModel {
|
||||
return &InstanceIDPRemoveWriteModel{
|
||||
IDPRemoveWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: instanceID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceIDPRemoveWriteModel) Reduce() error {
|
||||
return wm.IDPRemoveWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *InstanceIDPRemoveWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *instance.LDAPIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *instance.LDAPIDPChangedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *instance.IDPRemovedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceIDPRemoveWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.LDAPIDPAddedEventType,
|
||||
instance.LDAPIDPChangedEventType,
|
||||
instance.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
684
internal/command/instance_idp_test.go
Normal file
684
internal/command/instance_idp_test.go
Normal file
@@ -0,0 +1,684 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
id_mock "github.com/zitadel/zitadel/internal/id/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid password",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok all set",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddInstanceLDAPProvider(tt.args.ctx, tt.args.provider)
|
||||
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.id, id)
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
id string
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid id",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
func() eventstore.Command {
|
||||
t := true
|
||||
event, _ := instance.NewLDAPIDPChangedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
[]idp.LDAPIDPChanges{
|
||||
idp.ChangeLDAPName("new name"),
|
||||
idp.ChangeLDAPHost("new host"),
|
||||
idp.ChangeLDAPPort("new port"),
|
||||
idp.ChangeLDAPTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new baseDN"),
|
||||
idp.ChangeLDAPUserObjectClass("new userObjectClass"),
|
||||
idp.ChangeLDAPUserUniqueAttribute("new userUniqueAttribute"),
|
||||
idp.ChangeLDAPAdmin("new admin"),
|
||||
idp.ChangeLDAPPassword(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("new password"),
|
||||
}),
|
||||
idp.ChangeLDAPAttributes(idp.LDAPAttributeChanges{
|
||||
IDAttribute: stringPointer("new id"),
|
||||
FirstNameAttribute: stringPointer("new firstName"),
|
||||
LastNameAttribute: stringPointer("new lastName"),
|
||||
DisplayNameAttribute: stringPointer("new displayName"),
|
||||
NickNameAttribute: stringPointer("new nickName"),
|
||||
PreferredUsernameAttribute: stringPointer("new preferredUsername"),
|
||||
EmailAttribute: stringPointer("new email"),
|
||||
EmailVerifiedAttribute: stringPointer("new emailVerified"),
|
||||
PhoneAttribute: stringPointer("new phone"),
|
||||
PhoneVerifiedAttribute: stringPointer("new phoneVerified"),
|
||||
PreferredLanguageAttribute: stringPointer("new preferredLanguage"),
|
||||
AvatarURLAttribute: stringPointer("new avatarURL"),
|
||||
ProfileAttribute: stringPointer("new profile"),
|
||||
}),
|
||||
idp.ChangeLDAPOptions(idp.OptionChanges{
|
||||
IsCreationAllowed: &t,
|
||||
IsLinkingAllowed: &t,
|
||||
IsAutoCreation: &t,
|
||||
IsAutoUpdate: &t,
|
||||
}),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("new name", "instance1")),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "new name",
|
||||
Host: "new host",
|
||||
Port: "new port",
|
||||
TLS: true,
|
||||
BaseDN: "new baseDN",
|
||||
UserObjectClass: "new userObjectClass",
|
||||
UserUniqueAttribute: "new userUniqueAttribute",
|
||||
Admin: "new admin",
|
||||
Password: "new password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "new id",
|
||||
FirstNameAttribute: "new firstName",
|
||||
LastNameAttribute: "new lastName",
|
||||
DisplayNameAttribute: "new displayName",
|
||||
NickNameAttribute: "new nickName",
|
||||
PreferredUsernameAttribute: "new preferredUsername",
|
||||
EmailAttribute: "new email",
|
||||
EmailVerifiedAttribute: "new emailVerified",
|
||||
PhoneAttribute: "new phone",
|
||||
PhoneVerifiedAttribute: "new phoneVerified",
|
||||
PreferredLanguageAttribute: "new preferredLanguage",
|
||||
AvatarURLAttribute: "new avatarURL",
|
||||
ProfileAttribute: "new profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateInstanceLDAPProvider(tt.args.ctx, tt.args.id, tt.args.provider)
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
204
internal/command/org_idp.go
Normal file
204
internal/command/org_idp.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func (c *Commands) AddOrgLDAPProvider(ctx context.Context, resourceOwner string, provider LDAPProvider) (string, *domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
id, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddOrgLDAPProvider(orgAgg, resourceOwner, id, provider))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return id, pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateOrgLDAPProvider(ctx context.Context, resourceOwner, id string, provider LDAPProvider) (*domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareUpdateOrgLDAPProvider(orgAgg, resourceOwner, id, provider))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cmds) == 0 {
|
||||
// no change, so return directly
|
||||
return &domain.ObjectDetails{}, nil
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeleteOrgProvider(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareDeleteOrgProvider(orgAgg, resourceOwner, id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddOrgLDAPProvider(a *org.Aggregate, resourceOwner, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAfdd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SDVg2", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sv31s", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdgf4", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-AEG2w", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAD5n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Password = strings.TrimSpace(provider.Password); provider.Password == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdf5h", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPOrgIDPWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.Password), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{
|
||||
org.NewLDAPIDPAddedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
secret,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareUpdateOrgLDAPProvider(a *org.Aggregate, resourceOwner, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if id = strings.TrimSpace(id); id == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Dgdbs", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Sffgd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Dz62d", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-vb3ss", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-hbere", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-ASFt6", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-DG45z", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPOrgIDPWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-ASF3F", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
event, err := writeModel.NewChangedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
writeModel.Name,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.Password,
|
||||
c.idpConfigEncryption,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return []eventstore.Command{event}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareDeleteOrgProvider(a *org.Aggregate, resourceOwner, id string) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewOrgIDPRemoveWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-Se3tg", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
return []eventstore.Command{org.NewIDPRemovedEvent(ctx, &a.Aggregate, id, writeModel.name)}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
163
internal/command/org_idp_model.go
Normal file
163
internal/command/org_idp_model.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
type OrgLDAPIDPWriteModel struct {
|
||||
LDAPIDPWriteModel
|
||||
}
|
||||
|
||||
func NewLDAPOrgIDPWriteModel(orgID, id string) *OrgLDAPIDPWriteModel {
|
||||
return &OrgLDAPIDPWriteModel{
|
||||
LDAPIDPWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) Reduce() error {
|
||||
return wm.LDAPIDPWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.LDAPIDPAddedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *org.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *org.IDPRemovedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.LDAPIDPWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(org.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
org.LDAPIDPAddedEventType,
|
||||
org.LDAPIDPChangedEventType,
|
||||
org.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) (*org.LDAPIDPChangedEvent, error) {
|
||||
|
||||
changes, err := wm.LDAPIDPWriteModel.NewChanges(
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
secretCrypto,
|
||||
attributes,
|
||||
options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
changeEvent, err := org.NewLDAPIDPChangedEvent(ctx, aggregate, id, oldName, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type OrgIDPRemoveWriteModel struct {
|
||||
IDPRemoveWriteModel
|
||||
}
|
||||
|
||||
func NewOrgIDPRemoveWriteModel(orgID, id string) *OrgIDPRemoveWriteModel {
|
||||
return &OrgIDPRemoveWriteModel{
|
||||
IDPRemoveWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgIDPRemoveWriteModel) Reduce() error {
|
||||
return wm.IDPRemoveWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgIDPRemoveWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.LDAPIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *org.LDAPIDPChangedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *org.IDPRemovedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgIDPRemoveWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(org.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
org.LDAPIDPAddedEventType,
|
||||
org.LDAPIDPChangedEventType,
|
||||
org.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
698
internal/command/org_idp_test.go
Normal file
698
internal/command/org_idp_test.go
Normal file
@@ -0,0 +1,698 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
id_mock "github.com/zitadel/zitadel/internal/id/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid password",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok all set",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddOrgLDAPProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.provider)
|
||||
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.id, id)
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
id string
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid id",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
func() eventstore.Command {
|
||||
t := true
|
||||
event, _ := org.NewLDAPIDPChangedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
[]idp.LDAPIDPChanges{
|
||||
idp.ChangeLDAPName("new name"),
|
||||
idp.ChangeLDAPHost("new host"),
|
||||
idp.ChangeLDAPPort("new port"),
|
||||
idp.ChangeLDAPTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new baseDN"),
|
||||
idp.ChangeLDAPUserObjectClass("new userObjectClass"),
|
||||
idp.ChangeLDAPUserUniqueAttribute("new userUniqueAttribute"),
|
||||
idp.ChangeLDAPAdmin("new admin"),
|
||||
idp.ChangeLDAPPassword(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("new password"),
|
||||
}),
|
||||
idp.ChangeLDAPAttributes(idp.LDAPAttributeChanges{
|
||||
IDAttribute: stringPointer("new id"),
|
||||
FirstNameAttribute: stringPointer("new firstName"),
|
||||
LastNameAttribute: stringPointer("new lastName"),
|
||||
DisplayNameAttribute: stringPointer("new displayName"),
|
||||
NickNameAttribute: stringPointer("new nickName"),
|
||||
PreferredUsernameAttribute: stringPointer("new preferredUsername"),
|
||||
EmailAttribute: stringPointer("new email"),
|
||||
EmailVerifiedAttribute: stringPointer("new emailVerified"),
|
||||
PhoneAttribute: stringPointer("new phone"),
|
||||
PhoneVerifiedAttribute: stringPointer("new phoneVerified"),
|
||||
PreferredLanguageAttribute: stringPointer("new preferredLanguage"),
|
||||
AvatarURLAttribute: stringPointer("new avatarURL"),
|
||||
ProfileAttribute: stringPointer("new profile"),
|
||||
}),
|
||||
idp.ChangeLDAPOptions(idp.OptionChanges{
|
||||
IsCreationAllowed: &t,
|
||||
IsLinkingAllowed: &t,
|
||||
IsAutoCreation: &t,
|
||||
IsAutoUpdate: &t,
|
||||
}),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("new name", "org1")),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "new name",
|
||||
Host: "new host",
|
||||
Port: "new port",
|
||||
TLS: true,
|
||||
BaseDN: "new baseDN",
|
||||
UserObjectClass: "new userObjectClass",
|
||||
UserUniqueAttribute: "new userUniqueAttribute",
|
||||
Admin: "new admin",
|
||||
Password: "new password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "new id",
|
||||
FirstNameAttribute: "new firstName",
|
||||
LastNameAttribute: "new lastName",
|
||||
DisplayNameAttribute: "new displayName",
|
||||
NickNameAttribute: "new nickName",
|
||||
PreferredUsernameAttribute: "new preferredUsername",
|
||||
EmailAttribute: "new email",
|
||||
EmailVerifiedAttribute: "new emailVerified",
|
||||
PhoneAttribute: "new phone",
|
||||
PhoneVerifiedAttribute: "new phoneVerified",
|
||||
PreferredLanguageAttribute: "new preferredLanguage",
|
||||
AvatarURLAttribute: "new avatarURL",
|
||||
ProfileAttribute: "new profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateOrgLDAPProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider)
|
||||
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 stringPointer(s string) *string {
|
||||
return &s
|
||||
}
|
Reference in New Issue
Block a user