| @@ -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}, | |||