Skip to content

Commit

Permalink
escape filter meta chars to prevent ldap injection
Browse files Browse the repository at this point in the history
  • Loading branch information
summerQLin committed Sep 15, 2015
1 parent 7711f57 commit 6e8bb39
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 18 deletions.
46 changes: 33 additions & 13 deletions auth_server/authn/ldap_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ package authn
import (
"bytes"
"crypto/tls"
b64 "encoding/base64"
"fmt"
"io/ioutil"
"strings"

"github.com/go-ldap/ldap"
"github.com/golang/glog"
)

type LDAPAuthConfig struct {
Addr string `yaml:"addr,omitempty"`
StartTLS bool `yaml:"start_tls,omitempty"`
Base string `yaml:"base,omitempty"`
Filter string `yaml:"filter,omitempty"`
Bind_DN string `yaml:"bind_dn,omitempty"`
Password string `yaml:"password,omitempty"`
GroupBaseDN string `yaml:"group_base_dn,omitempty"`
GroupFilter string `yaml:"group_filter,omitempty"`
Addr string `yaml:"addr,omitempty"`
StartTLS bool `yaml:"tls,omitempty"`
Base string `yaml:"base,omitempty"`
Filter string `yaml:"filter,omitempty"`
BindDN string `yaml:"bind_dn,omitempty"`
BindPasswordFile string `yaml:"bind_password_file,omitempty"`
GroupBaseDN string `yaml:"group_base_dn,omitempty"`
GroupFilter string `yaml:"group_filter,omitempty"`
}

type LDAPAuth struct {
Expand Down Expand Up @@ -64,6 +64,8 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
return false, bindErr
}

account = la.escapeAccountInput(account)

filter := la.getFilter(account)
accountEntryDN, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &[]string{})
if uSearchErr != nil {
Expand All @@ -85,17 +87,35 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
}

func (la *LDAPAuth) bindReadOnlyUser(l *ldap.Conn) error {
if la.config.Bind_DN != "" {
glog.V(2).Infof("Bind read-only user")
sDec, _ := b64.StdEncoding.DecodeString(la.config.Password)
err := l.Bind(la.config.Bind_DN, string(sDec))
if la.config.BindDN != "" {
password, err := ioutil.ReadFile(la.config.BindPasswordFile)
if err != nil {
return err
}
glog.V(2).Infof("Bind read-only user %s", string(password))
err = l.Bind(la.config.BindDN, string(password))
if err != nil {
return err
}
}
return nil
}

//To prevent LDAP injection, some characters must be escaped for searching
//e.g. char '/' will be replaced by hex '\5c'
//Filter meta chars are choosen based on filter complier code
//https://github.com/go-ldap/ldap/blob/master/filter.go#L159
func (la *LDAPAuth) escapeAccountInput(account string) string {
filterMetaStr := []string{"\\", "(", ")", "!", "*", "&", "|", "=", ">", "<", "~"}
for _, str := range filterMetaStr {
if strings.Contains(account, str) {
hex := fmt.Sprintf("%x", str)
account = strings.NewReplacer(str, "\\"+hex).Replace(account)
}
}
return account
}

func (la *LDAPAuth) ldapConnection() (*ldap.Conn, error) {
glog.V(2).Infof("Dial: starting...%s", la.config.Addr)
l, err := ldap.Dial("tcp", fmt.Sprintf("%s", la.config.Addr))
Expand Down
10 changes: 5 additions & 5 deletions examples/ldap_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ users:
"": {}
ldap_auth:
addr: ldap.example.com:389
start_tls: true
tls: true
base: o=example.com
filter: (|(&(uid=${account})(objectClass=person))(&(cn=${account})(objectClass=Application)))
# in case bind DN and password is required for querying directory server, the password is Base64 encoded
bind_dn: uid=readonlyuser,ou=people,o=example.com
password: MTIz
filter: (&(uid=${account})(objectClass=person))
# in case bind DN and password is required for querying directory server
bind_dn:
bind_password_file:
acl:
- match:
account: ""
Expand Down

0 comments on commit 6e8bb39

Please sign in to comment.