|
|
|
@ -8,11 +8,11 @@ package ldap
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"crypto/tls" |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"strings" |
|
|
|
|
"net" |
|
|
|
|
"net/url" |
|
|
|
|
"errors" |
|
|
|
|
"strings" |
|
|
|
|
|
|
|
|
|
"gopkg.in/ldap.v2" |
|
|
|
|
|
|
|
|
@ -21,7 +21,6 @@ import (
|
|
|
|
|
|
|
|
|
|
type SecurityProtocol int |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Basic LDAP authentication service
|
|
|
|
|
type Source struct { |
|
|
|
|
Name string // canonical name (ie. corporate.ad)
|
|
|
|
@ -109,29 +108,29 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
|
|
|
|
|
|
|
|
|
|
func dial(ls *Source) (*ldap.Conn, error) { |
|
|
|
|
log.Trace("Dialing %s (skip cert verification: %v, start TLS: %v)", ls.URL, ls.SkipVerify, ls.StartTLS) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// URL Parsing
|
|
|
|
|
ldapUrl := ls.URL |
|
|
|
|
ldapiHost := "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fix ldapi URLs (1/2): ~ by removing and saving the host part for later.
|
|
|
|
|
if strings.HasPrefix(ldapUrl, "ldapi://") { |
|
|
|
|
x := strings.IndexAny(ldapUrl[8:], "/?#") |
|
|
|
|
if x >= 0 { |
|
|
|
|
ldapiHost = ldapUrl[8:8+x] |
|
|
|
|
ldapiHost = ldapUrl[8 : 8+x] |
|
|
|
|
ldapUrl = "ldapi://" + ldapUrl[8+x:] |
|
|
|
|
} else { |
|
|
|
|
ldapiHost = ldapUrl[8:] |
|
|
|
|
ldapUrl = "ldapi://" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Parse the URL
|
|
|
|
|
u, err := url.Parse(ldapUrl) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fix ldapi URLs (2/2): ~ by injecting the saved and decoded host part into the parsed URL struct.
|
|
|
|
|
if ldapiHost != "" { |
|
|
|
|
u.Host, err = url.QueryUnescape(ldapiHost) |
|
|
|
@ -139,12 +138,11 @@ func dial(ls *Source) (*ldap.Conn, error) {
|
|
|
|
|
return nil, fmt.Errorf("Unescape hostpart of ldapi URL: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if u.User != nil || u.Path != "" || u.Fragment != "" || u.RawQuery != "" || u.Opaque != "" { |
|
|
|
|
return nil, errors.New("LDAP URLs (for now) do not support pathes, fragments, querries or opaque form") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// Dial
|
|
|
|
|
// ldapI
|
|
|
|
|
if u.Scheme == "ldapi" { |
|
|
|
@ -152,56 +150,56 @@ func dial(ls *Source) (*ldap.Conn, error) {
|
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("Dial: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return conn, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Common stuff dor ldap / ldapS
|
|
|
|
|
host, port, err := net.SplitHostPort(u.Host) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("Failed splitting adress in host and port part: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tlsCfg := &tls.Config{ |
|
|
|
|
ServerName: host, |
|
|
|
|
InsecureSkipVerify: ls.SkipVerify, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ldapS
|
|
|
|
|
if u.Scheme == "ldaps" { |
|
|
|
|
if port == "" { |
|
|
|
|
port = "636" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conn, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", host, port), tlsCfg) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("DialTLS: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return conn, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ldap
|
|
|
|
|
if u.Scheme == "ldap" { |
|
|
|
|
if port == "" { |
|
|
|
|
port = "389" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conn, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("Dial: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ls.StartTLS == ls.StartTLS { |
|
|
|
|
if err = conn.StartTLS(tlsCfg); err != nil { |
|
|
|
|
conn.Close() |
|
|
|
|
return nil, fmt.Errorf("StartTLS: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return conn, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil, errors.New("The URL dos not has a valid LDAP scheme ('ldap://', 'ldaps://' or 'ldapi://'") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|