|
|
@ -9,6 +9,7 @@ package ldap |
|
|
|
import ( |
|
|
|
"crypto/tls" |
|
|
|
"fmt" |
|
|
|
"strings" |
|
|
|
|
|
|
|
"github.com/gogits/gogs/modules/ldap" |
|
|
|
"github.com/gogits/gogs/modules/log" |
|
|
@ -33,6 +34,28 @@ type Source struct { |
|
|
|
Enabled bool // if this source is disabled
|
|
|
|
} |
|
|
|
|
|
|
|
func (ls *Source) sanitizedUserQuery(username string) (string, bool) { |
|
|
|
// See http://tools.ietf.org/search/rfc4515
|
|
|
|
badCharacters := "\x00()*\\" |
|
|
|
if strings.ContainsAny(username, badCharacters) { |
|
|
|
log.Debug("'%s' contains invalid query characters. Aborting.", username) |
|
|
|
return "", false |
|
|
|
} |
|
|
|
|
|
|
|
return fmt.Sprintf(ls.Filter, username), true |
|
|
|
} |
|
|
|
|
|
|
|
func (ls *Source) sanitizedUserDN(username string) (string, bool) { |
|
|
|
// See http://tools.ietf.org/search/rfc4514: "special characters"
|
|
|
|
badCharacters := "\x00()*\\,='\"#+;<> " |
|
|
|
if strings.ContainsAny(username, badCharacters) { |
|
|
|
log.Debug("'%s' contains invalid DN characters. Aborting.", username) |
|
|
|
return "", false |
|
|
|
} |
|
|
|
|
|
|
|
return fmt.Sprintf(ls.UserDN, username), true |
|
|
|
} |
|
|
|
|
|
|
|
func (ls *Source) FindUserDN(name string) (string, bool) { |
|
|
|
l, err := ldapDial(ls) |
|
|
|
if err != nil { |
|
|
@ -55,7 +78,11 @@ func (ls *Source) FindUserDN(name string) (string, bool) { |
|
|
|
} |
|
|
|
|
|
|
|
// A search for the user.
|
|
|
|
userFilter := fmt.Sprintf(ls.Filter, name) |
|
|
|
userFilter, ok := ls.sanitizedUserQuery(name) |
|
|
|
if !ok { |
|
|
|
return "", false |
|
|
|
} |
|
|
|
|
|
|
|
log.Trace("Searching using filter %s", userFilter) |
|
|
|
search := ldap.NewSearchRequest( |
|
|
|
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, |
|
|
@ -85,7 +112,12 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str |
|
|
|
var userDN string |
|
|
|
if directBind { |
|
|
|
log.Trace("LDAP will bind directly via UserDN template: %s", ls.UserDN) |
|
|
|
userDN = fmt.Sprintf(ls.UserDN, name) |
|
|
|
|
|
|
|
var ok bool |
|
|
|
userDN, ok = ls.sanitizedUserDN(name) |
|
|
|
if !ok { |
|
|
|
return "", "", "", false, false |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Trace("LDAP will use BindDN.") |
|
|
|
|
|
|
@ -112,7 +144,11 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str |
|
|
|
} |
|
|
|
|
|
|
|
log.Trace("Bound successfully with userDN: %s", userDN) |
|
|
|
userFilter := fmt.Sprintf(ls.Filter, name) |
|
|
|
userFilter, ok := ls.sanitizedUserQuery(name) |
|
|
|
if !ok { |
|
|
|
return "", "", "", false, false |
|
|
|
} |
|
|
|
|
|
|
|
search := ldap.NewSearchRequest( |
|
|
|
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter, |
|
|
|
[]string{ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}, |
|
|
|