diff --git a/connector/ldap/ldap.go b/connector/ldap/ldap.go index 856949d240..fd7828fc41 100644 --- a/connector/ldap/ldap.go +++ b/connector/ldap/ldap.go @@ -62,6 +62,8 @@ import ( type UserMatcher struct { UserAttr string `json:"userAttr"` GroupAttr string `json:"groupAttr"` + // Work only if UserAttr is 'memberOf' and GroupAttr is dn + GroupPrefix string `json:"groupPrefix"` } // Config holds configuration options for LDAP logins. @@ -593,6 +595,49 @@ func (c *ldapConnector) groups(ctx context.Context, user ldap.Entry) ([]string, var groups []*ldap.Entry for _, matcher := range c.GroupSearch.UserMatchers { + // When we get groups from memberof user.s entity attribute, we may + // don.t want (Or don.t need) to perform extra search query for each group. + // Also when groupattr is dn (which implies memberof freeipa), we cannot use + // ldapsearch to retrieve group by DN (LDAP restriction) + if strings.ToLower(matcher.UserAttr) == "memberof" && + strings.ToLower(matcher.GroupAttr) == "dn" { + for _, attr := range c.getAttrs(user, matcher.UserAttr) { + // If group dn has no ends with group search base dn - ignore it. + // In FreeIPA case, it also can contain hbac, sudo rules, etc... + if !strings.HasSuffix(attr, c.GroupSearch.BaseDN) { + continue + } + + // Trim {NameAttr}= prefix and baseDN suffix to get group name. + // For NameAttr=cn and BaseDN=cn=groups,dc=example,dc=com : + // cn=groupname,cn=groups,dc=example,dc=com -> groupname + groupName := strings.TrimSuffix( + strings.TrimPrefix(attr, + fmt.Sprintf("%s=", c.GroupSearch.NameAttr)), + fmt.Sprintf(",%s", c.GroupSearch.BaseDN)) + + // Is it needed compability with GroupSearch.Filter? (r9odt) + if !strings.HasPrefix(groupName, matcher.GroupPrefix) { + continue + } + + // Append result to group list as ldap.Entry to process it next wihtout + // extra changes in code. + groups = append(groups, &ldap.Entry{ + DN: attr, + Attributes: []*ldap.EntryAttribute{ + { + Name: c.GroupSearch.NameAttr, + Values: []string{ + groupName, + }, + }, + }, + }) + } + continue + } + for _, attr := range c.getAttrs(user, matcher.UserAttr) { filter := fmt.Sprintf("(%s=%s)", matcher.GroupAttr, ldap.EscapeFilter(attr)) if c.GroupSearch.Filter != "" {