diff options
author | aboron <aboron@users.noreply.github.com> | 2017-05-29 22:33:50 -0400 |
---|---|---|
committer | 无闻 <u@gogs.io> | 2017-05-29 22:33:50 -0400 |
commit | dbb7e5464b6a9cad430b2f36b52e7674211f51cf (patch) | |
tree | 8f201849432a65d3a58e04ef2c92b7eedfbf7a24 /pkg/auth/ldap/ldap.go | |
parent | 11ad64f6cbdc489a49247604fe697dffaa090ac2 (diff) |
ldap: add check for group membership (#4398)
* Add standard LDAP group membership checking.
* Fix formatting, typo, grammer, and syntax errors
* Debugging done.
Gave up on locale file edits.
Diffstat (limited to 'pkg/auth/ldap/ldap.go')
-rw-r--r-- | pkg/auth/ldap/ldap.go | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/pkg/auth/ldap/ldap.go b/pkg/auth/ldap/ldap.go index 78cd66a4..25fddeb7 100644 --- a/pkg/auth/ldap/ldap.go +++ b/pkg/auth/ldap/ldap.go @@ -42,6 +42,11 @@ type Source struct { AttributesInBind bool // fetch attributes in bind context (not user) Filter string // Query filter to validate entry AdminFilter string // Query filter to check if user is admin + GroupsEnabled bool // if the group checking is enabled + GroupDN string // Group Search Base + GroupFilter string // Group Name Filter + GroupMemberUid string // Group Attribute containing array of UserUID + UserUID string // User Attribute listed in Group Enabled bool // if this source is disabled } @@ -67,6 +72,28 @@ func (ls *Source) sanitizedUserDN(username string) (string, bool) { return fmt.Sprintf(ls.UserDN, username), true } +func (ls *Source) sanitizedGroupFilter(group string) (string, bool) { + // See http://tools.ietf.org/search/rfc4515 + badCharacters := "\x00*\\" + if strings.ContainsAny(group, badCharacters) { + log.Trace("Group filter invalid query characters: %s", group) + return "", false + } + + return group, true +} + +func (ls *Source) sanitizedGroupDN(groupDn string) (string, bool) { + // See http://tools.ietf.org/search/rfc4514: "special characters" + badCharacters := "\x00()*\\'\"#+;<>" + if strings.ContainsAny(groupDn, badCharacters) || strings.HasPrefix(groupDn, " ") || strings.HasSuffix(groupDn, " ") { + log.Trace("Group DN contains invalid query characters: %s", groupDn) + return "", false + } + + return groupDn, true +} + func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) { log.Trace("Search for LDAP user: %s", name) if ls.BindDN != "" && ls.BindPassword != "" { @@ -194,15 +221,15 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str return "", "", "", "", false, false } - log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN) + log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.UserUID, userFilter, userDN) search := ldap.NewSearchRequest( userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter, - []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}, + []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.UserUID}, nil) sr, err := l.Search(search) if err != nil { - log.Error(4, "LDAP search failed: %v", err) + log.Error(4, "LDAP user search failed: %v", err) return "", "", "", "", false, false } else if len(sr.Entries) < 1 { if directBind { @@ -218,6 +245,48 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName) surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname) mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail) + uid := sr.Entries[0].GetAttributeValue(ls.UserUID) + + // Check group membership + if ls.GroupsEnabled { + groupFilter, ok := ls.sanitizedGroupFilter(ls.GroupFilter) + if !ok { + return "", "", "", "", false, false + } + groupDN, ok := ls.sanitizedGroupDN(ls.GroupDN) + if !ok { + return "", "", "", "", false, false + } + + log.Trace("Fetching groups '%v' with filter '%s' and base '%s'", ls.GroupMemberUid, groupFilter, groupDN) + groupSearch := ldap.NewSearchRequest( + groupDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, groupFilter, + []string{ls.GroupMemberUid}, + nil) + + srg, err := l.Search(groupSearch) + if err != nil { + log.Error(4, "LDAP group search failed: %v", err) + return "", "", "", "", false, false + } else if len(sr.Entries) < 1 { + log.Error(4, "LDAP group search failed: 0 entries") + return "", "", "", "", false, false + } + + isMember := false + for _,group := range srg.Entries { + for _,member := range group.GetAttributeValues(ls.GroupMemberUid) { + if member == uid { + isMember = true + } + } + } + + if !isMember { + log.Error(4, "LDAP group membership test failed") + return "", "", "", "", false, false + } + } isAdmin := false if len(ls.AdminFilter) > 0 { |