mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-25 15:09:27 -06:00
graph: Allow disabling user by adding to local group
* A new config option for disabling users with the options "none", "attribute" and "group". * When set to "none", there will be no enabledAttribute returned in user info and trying to change enabledAttribute will return an error * Disable/enable group name DN as config parameter * Adding/removing users to specified group on user update * Changing log level for service initialization failure to error * Adding helper methods to check if user is enabled/disabled + tests Fixes #5554
This commit is contained in:
@@ -60,7 +60,7 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Info().Err(err).Str("transport", "http").Msg("Failed to initialize server")
|
||||
logger.Error().Err(err).Str("transport", "http").Msg("Failed to initialize server")
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ type LDAP struct {
|
||||
UserNameAttribute string `yaml:"user_name_attribute" env:"LDAP_USER_SCHEMA_USERNAME;GRAPH_LDAP_USER_NAME_ATTRIBUTE" desc:"LDAP Attribute to use for username of users."`
|
||||
UserIDAttribute string `yaml:"user_id_attribute" env:"LDAP_USER_SCHEMA_ID;GRAPH_LDAP_USER_UID_ATTRIBUTE" desc:"LDAP Attribute to use as the unique ID for users. This should be a stable globally unique ID like a UUID."`
|
||||
UserEnabledAttribute string `yaml:"user_enabled_attribute" env:"LDAP_USER_ENABLED_ATTRIBUTE;GRAPH_USER_ENABLED_ATTRIBUTE" desc:"LDAP Attribute to use as a flag telling if the user is enabled or disabled."`
|
||||
DisableUserMechanism string `yaml:"disable_user_mechanism" env:"LDAP_DISABLE_USER_MECHANISM;GRAPH_DISABLE_USER_MECHANISM" desc:"An option to control the behavior for disabling users. Valid options are 'none', 'attribute' and 'group'. If set to 'group', disabling a user via API will add the user to the configured group for disabled users, if set to 'attribute' this will be done in the ldap user entry, if set to 'none' the disable request is not processed. Default is 'attribute'."`
|
||||
LdapDisabledUsersGroupDN string `yaml:"ldap_disabled_users_group_dn" env:"LDAP_DISABLED_USERS_GROUP_DN;GRAPH_DISABLED_USERS_GROUP_DN" desc:"The distinguished name of the group to which added users will be classified as disabled when 'disable_user_mechanism' is set to 'group'."`
|
||||
|
||||
GroupBaseDN string `yaml:"group_base_dn" env:"LDAP_GROUP_BASE_DN;GRAPH_LDAP_GROUP_BASE_DN" desc:"Search base DN for looking up LDAP groups."`
|
||||
GroupSearchScope string `yaml:"group_search_scope" env:"LDAP_GROUP_SCOPE;GRAPH_LDAP_GROUP_SEARCH_SCOPE" desc:"LDAP search scope to use when looking up groups. Supported scopes are 'base', 'one' and 'sub'."`
|
||||
|
||||
@@ -69,6 +69,8 @@ func DefaultConfig() *config.Config {
|
||||
// ideally this needs to be constant for the lifetime of a users
|
||||
UserIDAttribute: "owncloudUUID",
|
||||
UserEnabledAttribute: "ownCloudUserEnabled",
|
||||
DisableUserMechanism: "attribute",
|
||||
LdapDisabledUsersGroupDN: "cn=DisabledUsersGroup,ou=groups,o=libregraph-idm",
|
||||
GroupBaseDN: "ou=groups,o=libregraph-idm",
|
||||
GroupSearchScope: "sub",
|
||||
GroupFilter: "",
|
||||
|
||||
@@ -20,10 +20,29 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
givenNameAttribute = "givenname"
|
||||
surNameAttribute = "sn"
|
||||
_givenNameAttribute = "givenname"
|
||||
_surNameAttribute = "sn"
|
||||
_ldapGroupOfNamesAttribute = "(objectClass=groupOfNames)"
|
||||
_ldapGroupMemberAttribute = "member"
|
||||
)
|
||||
|
||||
// DisableUserMechanismType is used instead of directly using the string values from the configuration.
|
||||
type DisableUserMechanismType int64
|
||||
|
||||
// The different DisableMechanism* constants are used for managing the enabling/disabling of users.
|
||||
const (
|
||||
DisableMechanismNone DisableUserMechanismType = iota
|
||||
DisableMechanismAttribute
|
||||
DisableMechanismGroup
|
||||
)
|
||||
|
||||
var mechanismMap = map[string]DisableUserMechanismType{
|
||||
"": DisableMechanismNone,
|
||||
"none": DisableMechanismNone,
|
||||
"attribute": DisableMechanismAttribute,
|
||||
"group": DisableMechanismGroup,
|
||||
}
|
||||
|
||||
type LDAP struct {
|
||||
useServerUUID bool
|
||||
writeEnabled bool
|
||||
@@ -36,6 +55,9 @@ type LDAP struct {
|
||||
userScope int
|
||||
userAttributeMap userAttributeMap
|
||||
|
||||
disableUserMechanism DisableUserMechanismType
|
||||
localUserDisableGroupDN string
|
||||
|
||||
groupBaseDN string
|
||||
groupFilter string
|
||||
groupObjectClass string
|
||||
@@ -60,6 +82,17 @@ type userAttributeMap struct {
|
||||
|
||||
type ldapAttributeValues map[string][]string
|
||||
|
||||
// ParseDisableMechanismType checks that the configuration option for how to disable users is correct.
|
||||
func ParseDisableMechanismType(disableMechanism string) (DisableUserMechanismType, error) {
|
||||
disableMechanism = strings.ToLower(disableMechanism)
|
||||
t, ok := mechanismMap[disableMechanism]
|
||||
if !ok {
|
||||
return -1, errors.New("invalid configuration option for disable user mechanism")
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LDAP, error) {
|
||||
if config.UserDisplayNameAttribute == "" || config.UserIDAttribute == "" ||
|
||||
config.UserEmailAttribute == "" || config.UserNameAttribute == "" {
|
||||
@@ -71,8 +104,8 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD
|
||||
mail: config.UserEmailAttribute,
|
||||
userName: config.UserNameAttribute,
|
||||
accountEnabled: config.UserEnabledAttribute,
|
||||
givenName: givenNameAttribute,
|
||||
surname: surNameAttribute,
|
||||
givenName: _givenNameAttribute,
|
||||
surname: _surNameAttribute,
|
||||
}
|
||||
|
||||
if config.GroupNameAttribute == "" || config.GroupIDAttribute == "" {
|
||||
@@ -81,7 +114,7 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD
|
||||
gam := groupAttributeMap{
|
||||
name: config.GroupNameAttribute,
|
||||
id: config.GroupIDAttribute,
|
||||
member: "member",
|
||||
member: _ldapGroupMemberAttribute,
|
||||
memberSyntax: "dn",
|
||||
}
|
||||
|
||||
@@ -100,24 +133,31 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD
|
||||
return nil, fmt.Errorf("error setting up education resource config: %w", err)
|
||||
}
|
||||
|
||||
disableMechanismType, err := ParseDisableMechanismType(config.DisableUserMechanism)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error configuring disable user mechanism: %w", err)
|
||||
}
|
||||
|
||||
return &LDAP{
|
||||
useServerUUID: config.UseServerUUID,
|
||||
usePwModifyExOp: config.UsePasswordModExOp,
|
||||
userBaseDN: config.UserBaseDN,
|
||||
userFilter: config.UserFilter,
|
||||
userObjectClass: config.UserObjectClass,
|
||||
userScope: userScope,
|
||||
userAttributeMap: uam,
|
||||
groupBaseDN: config.GroupBaseDN,
|
||||
groupFilter: config.GroupFilter,
|
||||
groupObjectClass: config.GroupObjectClass,
|
||||
groupScope: groupScope,
|
||||
groupAttributeMap: gam,
|
||||
educationConfig: educationConfig,
|
||||
logger: logger,
|
||||
conn: lc,
|
||||
writeEnabled: config.WriteEnabled,
|
||||
refintEnabled: config.RefintEnabled,
|
||||
useServerUUID: config.UseServerUUID,
|
||||
usePwModifyExOp: config.UsePasswordModExOp,
|
||||
userBaseDN: config.UserBaseDN,
|
||||
userFilter: config.UserFilter,
|
||||
userObjectClass: config.UserObjectClass,
|
||||
userScope: userScope,
|
||||
userAttributeMap: uam,
|
||||
groupBaseDN: config.GroupBaseDN,
|
||||
groupFilter: config.GroupFilter,
|
||||
groupObjectClass: config.GroupObjectClass,
|
||||
groupScope: groupScope,
|
||||
groupAttributeMap: gam,
|
||||
educationConfig: educationConfig,
|
||||
disableUserMechanism: disableMechanismType,
|
||||
localUserDisableGroupDN: config.LdapDisabledUsersGroupDN,
|
||||
logger: logger,
|
||||
conn: lc,
|
||||
writeEnabled: config.WriteEnabled,
|
||||
refintEnabled: config.RefintEnabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -131,6 +171,10 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap
|
||||
return nil, ErrReadOnly
|
||||
}
|
||||
|
||||
if user.AccountEnabled != nil && i.disableUserMechanism == DisableMechanismNone {
|
||||
return nil, errors.New("accountEnabled option not compatible with backend disable user mechanism")
|
||||
}
|
||||
|
||||
ar, err := i.userToAddRequest(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -254,14 +298,34 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph.
|
||||
}
|
||||
}
|
||||
|
||||
// Behavior of enabling/disabling of users depends on the "disableUserMechanism" config option:
|
||||
//
|
||||
// "attribute": For the upstream user management service which modifies accountEnabled on the user entry
|
||||
// "group": Makes it possible for local admins to disable users by adding them to a special group
|
||||
if user.AccountEnabled != nil {
|
||||
boolString := strings.ToUpper(strconv.FormatBool(*user.AccountEnabled))
|
||||
ldapValue := e.GetEqualFoldAttributeValue(i.userAttributeMap.accountEnabled)
|
||||
updateNeeded = true
|
||||
if ldapValue != "" {
|
||||
mr.Replace(i.userAttributeMap.accountEnabled, []string{boolString})
|
||||
} else {
|
||||
mr.Add(i.userAttributeMap.accountEnabled, []string{boolString})
|
||||
switch i.disableUserMechanism {
|
||||
case DisableMechanismNone:
|
||||
return nil, errors.New("accountEnabled option not compatible with backend disable user mechanism")
|
||||
case DisableMechanismAttribute:
|
||||
boolString := strings.ToUpper(strconv.FormatBool(user.GetAccountEnabled()))
|
||||
ldapValue := e.GetEqualFoldAttributeValue(i.userAttributeMap.accountEnabled)
|
||||
if ldapValue != "" {
|
||||
mr.Replace(i.userAttributeMap.accountEnabled, []string{boolString})
|
||||
} else {
|
||||
mr.Add(i.userAttributeMap.accountEnabled, []string{boolString})
|
||||
}
|
||||
updateNeeded = true
|
||||
case DisableMechanismGroup:
|
||||
if user.GetAccountEnabled() {
|
||||
err = i.enableUser(logger, e.DN)
|
||||
} else {
|
||||
err = i.disableUser(logger, e.DN)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateNeeded = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +340,16 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.createUserModelFromLDAP(e), nil
|
||||
|
||||
returnUser := i.createUserModelFromLDAP(e)
|
||||
|
||||
// To avoid an ldap lookup for group membership, set the enabled flag to same as input value
|
||||
// since this would have been updated with group membership from the input anyway.
|
||||
if user.AccountEnabled != nil && i.disableUserMechanism != DisableMechanismNone {
|
||||
returnUser.AccountEnabled = user.AccountEnabled
|
||||
}
|
||||
|
||||
return returnUser, nil
|
||||
}
|
||||
|
||||
func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) {
|
||||
@@ -320,7 +393,7 @@ func (i *LDAP) getEntryByDN(dn string, attrs []string, filter string) (*ldap.Ent
|
||||
Msg("getEntryByDN")
|
||||
res, err := i.conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
i.logger.Error().Err(err).Str("backend", "ldap").Str("dn", dn).Msg("Search user by DN failed")
|
||||
i.logger.Error().Err(err).Str("backend", "ldap").Str("dn", dn).Msg("Search ldap by DN failed")
|
||||
return nil, errorcode.New(errorcode.ItemNotFound, err.Error())
|
||||
}
|
||||
if len(res.Entries) == 0 {
|
||||
@@ -404,6 +477,13 @@ func (i *LDAP) GetUser(ctx context.Context, nameOrID string, oreq *godata.GoData
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
if i.disableUserMechanism != DisableMechanismNone {
|
||||
userEnabled, err := i.UserEnabled(e)
|
||||
if err == nil {
|
||||
u.AccountEnabled = &userEnabled
|
||||
}
|
||||
}
|
||||
|
||||
exp, err := GetExpandValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -472,6 +552,10 @@ func (i *LDAP) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*lib
|
||||
}
|
||||
|
||||
users := make([]*libregraph.User, 0, len(res.Entries))
|
||||
usersEnabledState, err := i.usersEnabledState(res.Entries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, e := range res.Entries {
|
||||
u := i.createUserModelFromLDAP(e)
|
||||
@@ -479,6 +563,12 @@ func (i *LDAP) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*lib
|
||||
if u == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if i.disableUserMechanism != DisableMechanismNone {
|
||||
userEnabled := usersEnabledState[e.DN]
|
||||
u.AccountEnabled = &userEnabled
|
||||
}
|
||||
|
||||
if slices.Contains(exp, "memberOf") {
|
||||
userGroups, err := i.getGroupsForUser(e.DN)
|
||||
if err != nil {
|
||||
@@ -802,3 +892,135 @@ func replaceDN(fullDN *ldap.DN, newDN string) (string, error) {
|
||||
|
||||
return newDN, nil
|
||||
}
|
||||
|
||||
// CreateLDAPGroupByDN is a helper method specifically intended for creating a "system" group
|
||||
// for managing locally disabled users on service startup
|
||||
func (i *LDAP) CreateLDAPGroupByDN(dn string) error {
|
||||
ar := ldap.NewAddRequest(dn, nil)
|
||||
|
||||
attrs := map[string][]string{
|
||||
"objectClass": {"groupOfNames", "top"},
|
||||
"member": {""},
|
||||
}
|
||||
|
||||
for attrType, values := range attrs {
|
||||
ar.Attribute(attrType, values)
|
||||
}
|
||||
|
||||
return i.conn.Add(ar)
|
||||
}
|
||||
|
||||
func (i *LDAP) disableUser(logger log.Logger, userDN string) (err error) {
|
||||
group, err := i.getEntryByDN(i.localUserDisableGroupDN, []string{_ldapGroupMemberAttribute}, _ldapGroupOfNamesAttribute)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mr := ldap.ModifyRequest{DN: group.DN}
|
||||
mr.Add(_ldapGroupMemberAttribute, []string{userDN})
|
||||
|
||||
err = i.conn.Modify(&mr)
|
||||
var lerr *ldap.Error
|
||||
if errors.As(err, &lerr) {
|
||||
// If the user is already in the group, just log a message and return
|
||||
if lerr.ResultCode == ldap.LDAPResultAttributeOrValueExists {
|
||||
logger.Info().Msg("User already in group for disabled users")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *LDAP) enableUser(logger log.Logger, userDN string) (err error) {
|
||||
group, err := i.getEntryByDN(i.localUserDisableGroupDN, []string{_ldapGroupMemberAttribute}, _ldapGroupOfNamesAttribute)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mr := ldap.ModifyRequest{DN: group.DN}
|
||||
mr.Delete(_ldapGroupMemberAttribute, []string{userDN})
|
||||
|
||||
err = i.conn.Modify(&mr)
|
||||
var lerr *ldap.Error
|
||||
if errors.As(err, &lerr) {
|
||||
// If the user is not in the group, just log a message and return
|
||||
if lerr.ResultCode == ldap.LDAPResultNoSuchAttribute {
|
||||
logger.Info().Msg("User was not in group for disabled users")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *LDAP) userEnabledByAttribute(user *ldap.Entry) bool {
|
||||
enabledAttribute := booleanOrNil(user.GetEqualFoldAttributeValue(i.userAttributeMap.accountEnabled))
|
||||
|
||||
if enabledAttribute == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return *enabledAttribute
|
||||
}
|
||||
|
||||
func (i *LDAP) usersEnabledStateFromGroup(users []string) (usersEnabledState map[string]bool, err error) {
|
||||
group, err := i.getEntryByDN(i.localUserDisableGroupDN, []string{_ldapGroupMemberAttribute}, _ldapGroupOfNamesAttribute)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
usersEnabledState = make(map[string]bool, len(users))
|
||||
for _, user := range users {
|
||||
usersEnabledState[user] = true
|
||||
}
|
||||
|
||||
for _, memberDN := range group.GetEqualFoldAttributeValues(_ldapGroupMemberAttribute) {
|
||||
usersEnabledState[memberDN] = false
|
||||
}
|
||||
|
||||
return usersEnabledState, err
|
||||
}
|
||||
|
||||
// UserEnabled returns if a user is enabled. This can depend on a flag in the user entry or group membership
|
||||
func (i *LDAP) UserEnabled(user *ldap.Entry) (bool, error) {
|
||||
usersEnabledState, err := i.usersEnabledState([]*ldap.Entry{user})
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return usersEnabledState[user.DN], nil
|
||||
}
|
||||
|
||||
func (i *LDAP) usersEnabledState(users []*ldap.Entry) (usersEnabledState map[string]bool, err error) {
|
||||
usersEnabledState = make(map[string]bool, len(users))
|
||||
keys := make([]string, len(users))
|
||||
for index, user := range users {
|
||||
usersEnabledState[user.DN] = true
|
||||
keys[index] = user.DN
|
||||
}
|
||||
|
||||
switch i.disableUserMechanism {
|
||||
case DisableMechanismAttribute:
|
||||
for _, user := range users {
|
||||
usersEnabledState[user.DN] = i.userEnabledByAttribute(user)
|
||||
}
|
||||
|
||||
case DisableMechanismGroup:
|
||||
userDisabledGroupState, err := i.usersEnabledStateFromGroup(keys)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, user := range keys {
|
||||
usersEnabledState[user] = userDisabledGroupState[user]
|
||||
}
|
||||
}
|
||||
|
||||
return usersEnabledState, nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ func getMockedBackend(l ldap.Client, lc config.LDAP, logger *log.Logger) (*LDAP,
|
||||
return NewLDAPBackend(l, lc, logger)
|
||||
}
|
||||
|
||||
const (
|
||||
disableUsersGroup = "cn=DisabledUsersGroup,ou=groups,o=testing"
|
||||
groupSearchFilter = "(objectClass=groupOfNames)"
|
||||
)
|
||||
|
||||
var lconfig = config.LDAP{
|
||||
UserBaseDN: "ou=people,dc=test",
|
||||
UserObjectClass: "inetOrgPerson",
|
||||
@@ -31,6 +36,8 @@ var lconfig = config.LDAP{
|
||||
UserEmailAttribute: "mail",
|
||||
UserNameAttribute: "uid",
|
||||
UserEnabledAttribute: "userEnabledAttribute",
|
||||
LdapDisabledUsersGroupDN: disableUsersGroup,
|
||||
DisableUserMechanism: "attribute",
|
||||
|
||||
GroupBaseDN: "ou=groups,dc=test",
|
||||
GroupObjectClass: "groupOfNames",
|
||||
@@ -285,16 +292,20 @@ func TestGetUsers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUpdateUser(t *testing.T) {
|
||||
falseBool := false
|
||||
trueBool := true
|
||||
|
||||
type userProps struct {
|
||||
id string
|
||||
mail string
|
||||
displayName string
|
||||
onPremisesSamAccountName string
|
||||
accountEnabled bool
|
||||
accountEnabled *bool
|
||||
}
|
||||
type args struct {
|
||||
nameOrID string
|
||||
userProps userProps
|
||||
nameOrID string
|
||||
userProps userProps
|
||||
disableUserMechanism string
|
||||
}
|
||||
type mockInputs struct {
|
||||
funcName string
|
||||
@@ -359,7 +370,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
mail: "testuser@example.org",
|
||||
displayName: "testUser",
|
||||
onPremisesSamAccountName: "testUser",
|
||||
accountEnabled: true,
|
||||
accountEnabled: nil,
|
||||
},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
@@ -397,7 +408,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -445,7 +456,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -488,7 +499,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
mail: "testuser@example.org",
|
||||
displayName: "newName",
|
||||
onPremisesSamAccountName: "testUser",
|
||||
accountEnabled: true,
|
||||
accountEnabled: nil,
|
||||
},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
@@ -526,7 +537,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -574,7 +585,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -617,7 +628,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
mail: "testuser@example.org",
|
||||
displayName: "newName",
|
||||
onPremisesSamAccountName: "newName",
|
||||
accountEnabled: true,
|
||||
accountEnabled: nil,
|
||||
},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
@@ -659,7 +670,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -755,7 +766,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -797,15 +808,16 @@ func TestUpdateUser(t *testing.T) {
|
||||
args: args{
|
||||
nameOrID: "testUser",
|
||||
userProps: userProps{
|
||||
accountEnabled: false,
|
||||
accountEnabled: &falseBool,
|
||||
},
|
||||
disableUserMechanism: "attribute",
|
||||
},
|
||||
want: &userProps{
|
||||
id: "testUser",
|
||||
mail: "testuser@example.org",
|
||||
displayName: "testUser",
|
||||
onPremisesSamAccountName: "testUser",
|
||||
accountEnabled: false,
|
||||
accountEnabled: &falseBool,
|
||||
},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
@@ -921,6 +933,338 @@ func TestUpdateUser(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test disabling user as local admin",
|
||||
args: args{
|
||||
nameOrID: "testUser",
|
||||
userProps: userProps{
|
||||
accountEnabled: &falseBool,
|
||||
},
|
||||
disableUserMechanism: "group",
|
||||
},
|
||||
want: &userProps{
|
||||
id: "testUser",
|
||||
mail: "testuser@example.org",
|
||||
displayName: "testUser",
|
||||
onPremisesSamAccountName: "testUser",
|
||||
accountEnabled: &falseBool,
|
||||
},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
"ou=people,dc=test",
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
|
||||
[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute"},
|
||||
nil,
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "uid=name",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Values: []string{"testuser@example.org"},
|
||||
},
|
||||
{
|
||||
Name: "entryUUID",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "mail",
|
||||
Values: []string{"testuser@example.org"},
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
&ldap.SearchRequest{
|
||||
BaseDN: disableUsersGroup,
|
||||
Scope: 0,
|
||||
DerefAliases: 0,
|
||||
SizeLimit: 1,
|
||||
TimeLimit: 0,
|
||||
TypesOnly: false,
|
||||
Filter: groupSearchFilter,
|
||||
Attributes: []string{"member"},
|
||||
Controls: []ldap.Control(nil),
|
||||
},
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "uid=name",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "member",
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
funcName: "Modify",
|
||||
args: []interface{}{
|
||||
&ldap.ModifyRequest{
|
||||
DN: "uid=name",
|
||||
Changes: []ldap.Change{
|
||||
{
|
||||
Operation: ldap.AddAttribute,
|
||||
Modification: ldap.PartialAttribute{
|
||||
Type: "member",
|
||||
Vals: []string{"uid=name"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Controls: []ldap.Control(nil),
|
||||
},
|
||||
},
|
||||
returns: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
funcName: "Modify",
|
||||
args: []interface{}{
|
||||
&ldap.ModifyRequest{
|
||||
DN: "uid=name",
|
||||
Changes: []ldap.Change(nil),
|
||||
Controls: []ldap.Control(nil),
|
||||
},
|
||||
},
|
||||
returns: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
"uid=name",
|
||||
ldap.ScopeBaseObject,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
"(objectClass=inetOrgPerson)",
|
||||
[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute"},
|
||||
[]ldap.Control(nil),
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "uid=name",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "uid",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "displayname",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "entryUUID",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "mail",
|
||||
Values: []string{"testuser@example.org"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test enabling user as local admin",
|
||||
args: args{
|
||||
nameOrID: "testUser",
|
||||
userProps: userProps{
|
||||
accountEnabled: &trueBool,
|
||||
},
|
||||
disableUserMechanism: "group",
|
||||
},
|
||||
want: &userProps{
|
||||
id: "testUser",
|
||||
mail: "testuser@example.org",
|
||||
displayName: "testUser",
|
||||
onPremisesSamAccountName: "testUser",
|
||||
accountEnabled: &trueBool,
|
||||
},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
"ou=people,dc=test",
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
|
||||
[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute"},
|
||||
nil,
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "uid=name",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Values: []string{"testuser@example.org"},
|
||||
},
|
||||
{
|
||||
Name: "entryUUID",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "mail",
|
||||
Values: []string{"testuser@example.org"},
|
||||
},
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
&ldap.SearchRequest{
|
||||
BaseDN: disableUsersGroup,
|
||||
Scope: 0,
|
||||
DerefAliases: 0,
|
||||
SizeLimit: 1,
|
||||
TimeLimit: 0,
|
||||
TypesOnly: false,
|
||||
Filter: groupSearchFilter,
|
||||
Attributes: []string{"member"},
|
||||
Controls: []ldap.Control(nil),
|
||||
},
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "uid=name",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "member",
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
funcName: "Modify",
|
||||
args: []interface{}{
|
||||
&ldap.ModifyRequest{
|
||||
DN: "uid=name",
|
||||
Changes: []ldap.Change{
|
||||
{
|
||||
Operation: ldap.DeleteAttribute,
|
||||
Modification: ldap.PartialAttribute{
|
||||
Type: "member",
|
||||
Vals: []string{"uid=name"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Controls: []ldap.Control(nil),
|
||||
},
|
||||
},
|
||||
returns: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
funcName: "Modify",
|
||||
args: []interface{}{
|
||||
&ldap.ModifyRequest{
|
||||
DN: "uid=name",
|
||||
Changes: []ldap.Change(nil),
|
||||
Controls: []ldap.Control(nil),
|
||||
},
|
||||
},
|
||||
returns: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
"uid=name",
|
||||
ldap.ScopeBaseObject,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
"(objectClass=inetOrgPerson)",
|
||||
[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute"},
|
||||
[]ldap.Control(nil),
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "uid=name",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "uid",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "displayname",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "entryUUID",
|
||||
Values: []string{"testUser"},
|
||||
},
|
||||
{
|
||||
Name: "mail",
|
||||
Values: []string{"testuser@example.org"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -928,13 +1272,17 @@ func TestUpdateUser(t *testing.T) {
|
||||
for _, mock := range tt.ldapMocks {
|
||||
lm.On(mock.funcName, mock.args...).Return(mock.returns...)
|
||||
}
|
||||
i, _ := getMockedBackend(lm, lconfig, &logger)
|
||||
|
||||
ldapConfig := lconfig
|
||||
ldapConfig.DisableUserMechanism = tt.args.disableUserMechanism
|
||||
i, _ := getMockedBackend(lm, ldapConfig, &logger)
|
||||
|
||||
user := libregraph.User{
|
||||
Id: &tt.args.userProps.id,
|
||||
Mail: &tt.args.userProps.mail,
|
||||
DisplayName: &tt.args.userProps.displayName,
|
||||
OnPremisesSamAccountName: &tt.args.userProps.onPremisesSamAccountName,
|
||||
AccountEnabled: tt.args.userProps.accountEnabled,
|
||||
}
|
||||
|
||||
emptyString := ""
|
||||
@@ -947,7 +1295,10 @@ func TestUpdateUser(t *testing.T) {
|
||||
OnPremisesSamAccountName: &tt.want.onPremisesSamAccountName,
|
||||
Surname: &emptyString,
|
||||
GivenName: &emptyString,
|
||||
AccountEnabled: &tt.want.accountEnabled,
|
||||
}
|
||||
|
||||
if tt.want.accountEnabled != nil {
|
||||
want.AccountEnabled = *&tt.want.accountEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,3 +1308,214 @@ func TestUpdateUser(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersEnabledState(t *testing.T) {
|
||||
aliceEnabled := ldap.Entry{
|
||||
DN: "alice",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"TRUE"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
bobDisabled := ldap.Entry{
|
||||
DN: "bob",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
Values: []string{"FALSE"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
carolImplicitlyEnabled := ldap.Entry{
|
||||
DN: "carol",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: lconfig.UserEnabledAttribute,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type args struct {
|
||||
usersToCheck []*ldap.Entry
|
||||
expectedUsers map[string]bool
|
||||
disableUserMechanism string
|
||||
}
|
||||
type mockInputs struct {
|
||||
funcName string
|
||||
args []interface{}
|
||||
returns []interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want map[string]bool
|
||||
assertion assert.ErrorAssertionFunc
|
||||
ldapMocks []mockInputs
|
||||
}{
|
||||
{
|
||||
name: "Test no users",
|
||||
args: args{
|
||||
usersToCheck: []*ldap.Entry{},
|
||||
expectedUsers: map[string]bool{},
|
||||
disableUserMechanism: "attribute",
|
||||
},
|
||||
want: map[string]bool{},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{},
|
||||
},
|
||||
{
|
||||
name: "Test attribute enabled users",
|
||||
args: args{
|
||||
usersToCheck: []*ldap.Entry{&aliceEnabled, &bobDisabled, &carolImplicitlyEnabled},
|
||||
expectedUsers: map[string]bool{"alice": true, "bob": false, "carol": true},
|
||||
disableUserMechanism: "attribute",
|
||||
},
|
||||
want: map[string]bool{"alice": true, "bob": false, "carol": true},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{},
|
||||
},
|
||||
{
|
||||
name: "Test attribute enabled users not in disabled group",
|
||||
args: args{
|
||||
usersToCheck: []*ldap.Entry{&aliceEnabled, &bobDisabled, &carolImplicitlyEnabled},
|
||||
expectedUsers: map[string]bool{"alice": true, "bob": false, "carol": true},
|
||||
disableUserMechanism: "group",
|
||||
},
|
||||
want: map[string]bool{"alice": true, "bob": true, "carol": true},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
disableUsersGroup,
|
||||
ldap.ScopeBaseObject,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
groupSearchFilter,
|
||||
[]string{"member"},
|
||||
[]ldap.Control(nil),
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "cn=DisabledGroup",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "member",
|
||||
Values: []string{""},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test attribute enabled users in disabled group",
|
||||
args: args{
|
||||
usersToCheck: []*ldap.Entry{&aliceEnabled, &bobDisabled, &carolImplicitlyEnabled},
|
||||
expectedUsers: map[string]bool{"alice": true, "bob": false, "carol": true},
|
||||
disableUserMechanism: "group",
|
||||
},
|
||||
want: map[string]bool{"alice": false, "bob": true, "carol": false},
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.Nil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
disableUsersGroup,
|
||||
ldap.ScopeBaseObject,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
groupSearchFilter,
|
||||
[]string{"member"},
|
||||
[]ldap.Control(nil),
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "cn=DisabledGroup",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "member",
|
||||
Values: []string{"alice", "carol"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test local group disable when ldap is throwing error",
|
||||
args: args{
|
||||
usersToCheck: []*ldap.Entry{&aliceEnabled, &bobDisabled, &carolImplicitlyEnabled},
|
||||
expectedUsers: map[string]bool{"alice": true, "bob": false, "carol": true},
|
||||
disableUserMechanism: "group",
|
||||
},
|
||||
want: nil,
|
||||
assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
|
||||
return assert.NotNil(t, err, args...)
|
||||
},
|
||||
ldapMocks: []mockInputs{
|
||||
{
|
||||
funcName: "Search",
|
||||
args: []interface{}{
|
||||
ldap.NewSearchRequest(
|
||||
disableUsersGroup,
|
||||
ldap.ScopeBaseObject,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
groupSearchFilter,
|
||||
[]string{"member"},
|
||||
[]ldap.Control(nil),
|
||||
),
|
||||
},
|
||||
returns: []interface{}{
|
||||
nil,
|
||||
&ldap.Error{
|
||||
Err: fmt.Errorf("Very Problematic Problems"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
lm := &mocks.Client{}
|
||||
for _, mock := range tt.ldapMocks {
|
||||
lm.On(mock.funcName, mock.args...).Return(mock.returns...)
|
||||
}
|
||||
|
||||
ldapConfig := lconfig
|
||||
ldapConfig.DisableUserMechanism = tt.args.disableUserMechanism
|
||||
i, _ := getMockedBackend(lm, ldapConfig, &logger)
|
||||
|
||||
got, err := i.usersEnabledState(tt.args.usersToCheck)
|
||||
tt.assertion(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package svc
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
ldapv3 "github.com/go-ldap/ldap/v3"
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
ocisldap "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
|
||||
@@ -366,6 +368,35 @@ func setIdentityBackends(options Options, svc *Graph) error {
|
||||
svc.identityEducationBackend = errEduBackend
|
||||
}
|
||||
}
|
||||
|
||||
disableMechanismType, err := identity.ParseDisableMechanismType(options.Config.Identity.LDAP.DisableUserMechanism)
|
||||
if err != nil {
|
||||
options.Logger.Error().Err(err).Msg("Error initializing LDAP Backend")
|
||||
return err
|
||||
}
|
||||
|
||||
if disableMechanismType == identity.DisableMechanismGroup {
|
||||
options.Logger.Info().Msg("LocalUserDisable is true, will create group if not exists")
|
||||
err := lb.CreateLDAPGroupByDN(options.Config.Identity.LDAP.LdapDisabledUsersGroupDN)
|
||||
if err != nil {
|
||||
isAnError := false
|
||||
var lerr *ldapv3.Error
|
||||
if errors.As(err, &lerr) {
|
||||
if lerr.ResultCode != ldapv3.LDAPResultEntryAlreadyExists {
|
||||
isAnError = true
|
||||
}
|
||||
} else {
|
||||
isAnError = true
|
||||
}
|
||||
|
||||
if isAnError {
|
||||
msg := "error adding group for disabling users"
|
||||
options.Logger.Error().Err(err).Str("local_user_disable", options.Config.Identity.LDAP.LdapDisabledUsersGroupDN).Msg(msg)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
err := fmt.Errorf("unknown identity backend: '%s'", options.Config.Identity.Backend)
|
||||
options.Logger.Err(err)
|
||||
|
||||
Reference in New Issue
Block a user