mirror of
https://github.com/minio/minio.git
synced 2024-12-23 21:55:53 -05:00
Identity LDAP: Allow multiple search base DNs (#14191)
This change allows the MinIO server to lookup users in different directory sub-trees by allowing specification of multiple search bases separated by semicolons.
This commit is contained in:
parent
d2e5f01542
commit
7dfa565d00
@ -540,7 +540,7 @@ func (c *SiteReplicationSys) GetIDPSettings(ctx context.Context) madmin.IDPSetti
|
||||
s := madmin.IDPSettings{}
|
||||
s.LDAP = madmin.LDAPSettings{
|
||||
IsLDAPEnabled: globalLDAPConfig.Enabled,
|
||||
LDAPUserDNSearchBase: globalLDAPConfig.UserDNSearchBaseDN,
|
||||
LDAPUserDNSearchBase: globalLDAPConfig.UserDNSearchBaseDistName,
|
||||
LDAPUserDNSearchFilter: globalLDAPConfig.UserDNSearchFilter,
|
||||
LDAPGroupSearchBase: globalLDAPConfig.GroupSearchBaseDistName,
|
||||
LDAPGroupSearchFilter: globalLDAPConfig.GroupSearchFilter,
|
||||
|
@ -37,7 +37,7 @@ ARGS:
|
||||
MINIO_IDENTITY_LDAP_SERVER_ADDR* (address) AD/LDAP server address e.g. "myldapserver.com:636"
|
||||
MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN (string) DN for LDAP read-only service account used to perform DN and group lookups
|
||||
MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD (string) Password for LDAP read-only service account used to perform DN and group lookups
|
||||
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN (string) Base LDAP DN to search for user DN
|
||||
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN (string) ";" separated list of user search base DNs e.g. "dc=myldapserver,dc=com"
|
||||
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER (string) Search filter to lookup user DN
|
||||
MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER (string) search filter for groups e.g. "(&(objectclass=groupOfNames)(memberUid=%s))"
|
||||
MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN (list) ";" separated list of group search base DNs e.g. "dc=myldapserver,dc=com"
|
||||
|
@ -51,8 +51,9 @@ type Config struct {
|
||||
ServerAddr string `json:"serverAddr"`
|
||||
|
||||
// User DN search parameters
|
||||
UserDNSearchBaseDN string `json:"userDNSearchBaseDN"`
|
||||
UserDNSearchFilter string `json:"userDNSearchFilter"`
|
||||
UserDNSearchBaseDistName string `json:"userDNSearchBaseDN"`
|
||||
UserDNSearchBaseDistNames []string `json:"-"`
|
||||
UserDNSearchFilter string `json:"userDNSearchFilter"`
|
||||
|
||||
// Group search parameters
|
||||
GroupSearchBaseDistName string `json:"groupSearchBaseDN"`
|
||||
@ -187,25 +188,32 @@ func (l *Config) lookupBind(conn *ldap.Conn) error {
|
||||
// search result in at most one result.
|
||||
func (l *Config) lookupUserDN(conn *ldap.Conn, username string) (string, error) {
|
||||
filter := strings.ReplaceAll(l.UserDNSearchFilter, "%s", ldap.EscapeFilter(username))
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
l.UserDNSearchBaseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
filter,
|
||||
[]string{}, // only need DN, so no pass no attributes here
|
||||
nil,
|
||||
)
|
||||
var foundDistNames []string
|
||||
for _, userSearchBase := range l.UserDNSearchBaseDistNames {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
userSearchBase,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
filter,
|
||||
[]string{}, // only need DN, so no pass no attributes here
|
||||
nil,
|
||||
)
|
||||
|
||||
searchResult, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
searchResult, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, entry := range searchResult.Entries {
|
||||
foundDistNames = append(foundDistNames, entry.DN)
|
||||
}
|
||||
}
|
||||
if len(searchResult.Entries) == 0 {
|
||||
if len(foundDistNames) == 0 {
|
||||
return "", fmt.Errorf("User DN for %s not found", username)
|
||||
}
|
||||
if len(searchResult.Entries) != 1 {
|
||||
if len(foundDistNames) != 1 {
|
||||
return "", fmt.Errorf("Multiple DNs for %s found - please fix the search filter", username)
|
||||
}
|
||||
return searchResult.Entries[0].DN, nil
|
||||
return foundDistNames[0], nil
|
||||
}
|
||||
|
||||
func (l *Config) searchForUserGroups(conn *ldap.Conn, username, bindDN string) ([]string, error) {
|
||||
@ -375,7 +383,12 @@ func (l Config) testConnection() error {
|
||||
|
||||
// IsLDAPUserDN determines if the given string could be a user DN from LDAP.
|
||||
func (l Config) IsLDAPUserDN(user string) bool {
|
||||
return strings.HasSuffix(user, ","+l.UserDNSearchBaseDN)
|
||||
for _, baseDN := range l.UserDNSearchBaseDistNames {
|
||||
if strings.HasSuffix(user, ","+baseDN) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetNonEligibleUserDistNames - find user accounts (DNs) that are no longer
|
||||
@ -505,15 +518,6 @@ func Lookup(kvs config.KVS, rootCAs *x509.CertPool) (l Config, err error) {
|
||||
if lookupBindDN != "" {
|
||||
l.LookupBindDN = lookupBindDN
|
||||
l.LookupBindPassword = lookupBindPassword
|
||||
|
||||
// User DN search configuration
|
||||
userDNSearchBaseDN := env.Get(EnvUserDNSearchBaseDN, kvs.Get(UserDNSearchBaseDN))
|
||||
userDNSearchFilter := env.Get(EnvUserDNSearchFilter, kvs.Get(UserDNSearchFilter))
|
||||
if userDNSearchFilter == "" || userDNSearchBaseDN == "" {
|
||||
return l, errors.New("In lookup bind mode, userDN search base DN and userDN search filter are both required")
|
||||
}
|
||||
l.UserDNSearchBaseDN = userDNSearchBaseDN
|
||||
l.UserDNSearchFilter = userDNSearchFilter
|
||||
}
|
||||
|
||||
// Test connection to LDAP server.
|
||||
@ -521,6 +525,16 @@ func Lookup(kvs config.KVS, rootCAs *x509.CertPool) (l Config, err error) {
|
||||
return l, fmt.Errorf("Connection test for LDAP server failed: %w", err)
|
||||
}
|
||||
|
||||
// User DN search configuration
|
||||
userDNSearchBaseDN := env.Get(EnvUserDNSearchBaseDN, kvs.Get(UserDNSearchBaseDN))
|
||||
userDNSearchFilter := env.Get(EnvUserDNSearchFilter, kvs.Get(UserDNSearchFilter))
|
||||
if userDNSearchFilter == "" || userDNSearchBaseDN == "" {
|
||||
return l, errors.New("UserDN search base DN and UserDN search filter are both required")
|
||||
}
|
||||
l.UserDNSearchBaseDistName = userDNSearchBaseDN
|
||||
l.UserDNSearchBaseDistNames = strings.Split(userDNSearchBaseDN, dnDelimiter)
|
||||
l.UserDNSearchFilter = userDNSearchFilter
|
||||
|
||||
// Group search params configuration
|
||||
grpSearchFilter := env.Get(EnvGroupSearchFilter, kvs.Get(GroupSearchFilter))
|
||||
grpSearchBaseDN := env.Get(EnvGroupSearchBaseDN, kvs.Get(GroupSearchBaseDN))
|
||||
|
@ -44,9 +44,9 @@ var (
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: UserDNSearchBaseDN,
|
||||
Description: `Base LDAP DN to search for user DN`,
|
||||
Description: `";" separated list of user search base DNs e.g. "dc=myldapserver,dc=com"`,
|
||||
Optional: true,
|
||||
Type: "string",
|
||||
Type: "list",
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: UserDNSearchFilter,
|
||||
|
Loading…
Reference in New Issue
Block a user