package ldap import ( "fmt" "regexp" ldap "github.com/go-ldap/ldap/v3" "github.com/pkg/errors" ) var ( // TimeLimitSeconds is the maximal time that LDAP will spend on a single // request. TimeLimitSeconds = 5 // SizeLimitEntries is the biggest number of results that is returned from a // search request. SizeLimitEntries = 100 // UserAttributes is the list of LDAP-Attributes that will be used for user // accounts. UserAttributes = []string{ "dn", // distinguished name, the unique "path" to a LDAP entry. "cn", // common name, human readable e.g. "Max Powers". "uid", // user identified, same as the username/login name. "uidNumber", // unique user ID, integer. "createTimestamp", // LDAP timestamp of when this entry was created. "modifyTimestamp", // LDAP timestemp of when this entry was last modified. } ) type Server struct { Host string Port int bindDN string bindPW string userBaseDN string } func (s *Server) newConn() (*ldap.Conn, error) { lc, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", s.Host, s.Port)) if err != nil { return nil, errors.Wrap(err, "Failed to dial LDAP") } err = lc.Bind(s.bindDN, s.bindPW) if err != nil { return nil, errors.Wrap(err, "Failed to bind service account to LDAP") } return lc, nil } // buildFilterForID builds an LDAP filter that searches for a user with a // specific uidNumber. func (s *Server) buildFilterForUserID(id int) string { return fmt.Sprintf("(&(objectClass=inetOrgPerson)(uidNumber=%d))", id) } func (s *Server) buildFilterForEmail(email string) string { reg := regexp.MustCompile("[^a-zA-Z0-9-+._@]+") email = reg.ReplaceAllString(email, "") return fmt.Sprintf("(&(objectClass=)())") // Conn is an LDAP connection. type Conn struct { *ldap.Conn } type User struct { Entry *ldap.Entry } // GetDisplayName implements User interface by returning the display name. func (u User) GetDisplayName() string { display := u.Entry.GetAttributeValue("displayName") if display == "" { display = u.Entry.GetAttributeValue("givenName") } if display == "" { display = u.Entry.GetAttributeValue("cn") } if display == "" { display = u.GetID() } return display } // GetID implements the User interface by returning the user ID. func (u User) GetID() string { id := u.Entry.GetAttributeValue("uid") return id } func (lc *Conn) UserByID(ID string) (User, error) { ldap.NewSearchRequest() } func (s *Server) UserByEmail(email string) (User, error) { lc, err := s.newConn() ldap.NewSearchRequest( s.userBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, SizeLimitEntries, TimeLimitSeconds, false, s.buildFilterForEmail(email), UserAttributes, nil) }