package main import ( "crypto/tls" "crypto/x509" "encoding/json" "encoding/pem" "flag" "fmt" "os" "path/filepath" "github.com/go-ldap/ldap/v3" ) type Output struct { Server string AuthSuccess bool Error string CertLoaded bool Results string } func GetFilePath(path string) string { // Check for empty filename if len(path) == 0 { return "" } // check if filename exists if _, err := os.Stat(path); os.IsNotExist((err)) { fmt.Printf("File '%s' not found, searching in same directory as binary\n", path) // if not, check that it exists in the same directory as the currently executing binary ex, err2 := os.Executable() if err2 != nil { //log.Printf("Error determining binary path : '%s'", err) return "" } binaryPath := filepath.Dir(ex) path = filepath.Join(binaryPath, path) } return path } func isFlagPassed(name string) bool { found := false flag.Visit(func(f *flag.Flag) { if f.Name == name { found = true } }) return found } func main() { var output Output // Process command line arguments server := flag.String("server", "ldap.example.com", "LDAP server to bind to") baseDN := flag.String("baseDN", "OU=Users,DC=example,DC=com", "Base DN to use when attempting to bind to AD") username := flag.String("username", "user", "Username to use when attempting to bind to AD") password := flag.String("password", "pass", "Password to use when attempting to bind to AD") certFile := flag.String("cert-file", "rootca.pem", "Filename to load trusted certificate from") flag.Parse() output.Server = *server // Get a copy of the system defined CA's system, err := x509.SystemCertPool() if err != nil { output.AuthSuccess = false output.Error = "failed to access system CA list" b, _ := json.Marshal(output) fmt.Println(string(b)) return } // only try to load certificate from file if the command line argument was specified if isFlagPassed("cert-file") { // Try to read the file cf, err := os.ReadFile(GetFilePath(*certFile)) if err != nil { output.AuthSuccess = false output.Error = err.Error() b, _ := json.Marshal(output) fmt.Println(string(b)) return } // Get the certificate from the file cpb, _ := pem.Decode(cf) crt, err := x509.ParseCertificate(cpb.Bytes) if err != nil { output.AuthSuccess = false output.Error = err.Error() b, _ := json.Marshal(output) fmt.Println(string(b)) return } // Add custom certificate to the system cert pool system.AddCert(crt) /* ok := system.AppendCertsFromPEM(crt) if !ok { output.AuthSuccess = false output.Error = "failed to parse WSDC intermediate certificate" b, _ := json.Marshal(output) fmt.Println(string(b)) return } */ output.CertLoaded = true } // Start trying to use ldap package // Set up TLS to use our custom certificate authority passed in cli argument tlsConfig := &tls.Config{ RootCAs: system, } // try connecting to AD via TLS and our custom certificate authority ldaps, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:636", *server), tlsConfig) if err != nil { output.AuthSuccess = false output.Error = fmt.Sprintf("Dial Error: %s", err) b, _ := json.Marshal(output) fmt.Println(string(b)) return } defer ldaps.Close() // try to bind to AD err = ldaps.Bind(*username, *password) if err != nil { output.AuthSuccess = false output.Error = fmt.Sprintf("Bind Error: %s", err) b, _ := json.Marshal(output) fmt.Println(string(b)) return } searchReq := ldap.NewSearchRequest( *baseDN, ldap.ScopeBaseObject, // you can also use ldap.ScopeWholeSubtree ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", []string{}, nil, ) result, err := ldaps.Search(searchReq) if err != nil { output.AuthSuccess = false output.Error = fmt.Sprintf("Search Error: %s", err) b, _ := json.Marshal(output) fmt.Println(string(b)) return } if len(result.Entries) == 0 { output.AuthSuccess = false output.Error = "No search results" b, _ := json.Marshal(output) fmt.Println(string(b)) return } else { output.AuthSuccess = true output.Results = fmt.Sprintf("Search result count: %d", len(result.Entries)) b, _ := json.Marshal(output) fmt.Println(string(b)) return } /* config := &auth.Config{ Server: *server, Port: 636, BaseDN: *baseDN, Security: auth.SecurityTLS, RootCAs: system, } //fmt.Printf("Connecting to ldap server '%s' with DN '%s' on port 636\n", *server, *baseDN) status, err := auth.Authenticate(config, *username, *password) if err != nil { //handle err //fmt.Println("Error : %s", err) output.Error = err.Error() } output.AuthSuccess = status b, _ := json.Marshal(output) fmt.Println(string(b)) */ }