package ldap import ( "crypto/tls" "fmt" "github.com/go-ldap/ldap/v3" ) type Authentication struct { Cfg *Config } func NewAuthentication(config Config) Authentication { a := Authentication{ Cfg: &config, } return a } func (a Authentication) open() (*ldap.Conn, error) { conn, err := ldap.DialURL(a.Cfg.URL) if err != nil { return nil, err } if a.Cfg.StartTLS { // Reconnect with TLS err = conn.StartTLS(&tls.Config{InsecureSkipVerify: true}) if err != nil { return nil, err } } err = conn.Bind(a.Cfg.BindUser, a.Cfg.BindPass) if err != nil { return nil, err } return conn, nil } func (a Authentication) close(conn *ldap.Conn) { if conn != nil { conn.Close() } } func (a Authentication) CheckLogin(username, password string) bool { return a.CheckCustomLogin("sAMAccountName", username, password) } func (a Authentication) CheckCustomLogin(userIdentifier, username, password string) bool { client, err := a.open() if err != nil { return false } defer a.close(client) // Search for the given username searchRequest := ldap.NewSearchRequest( a.Cfg.BaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, fmt.Sprintf("(&(objectClass=organizationalPerson)(%s=%s))", userIdentifier, username), []string{"dn", "userAccountControl"}, nil, ) sr, err := client.Search(searchRequest) if err != nil { return false } if len(sr.Entries) != 1 { return false } userDN := sr.Entries[0].DN // Check if user is disabled, if so deny login uac := sr.Entries[0].GetAttributeValue("userAccountControl") if uac != "" && IsLdapUserDisabled(uac) { return false } // Bind as the user to verify their password err = client.Bind(userDN, password) if err != nil { return false } return true }