package models import ( "crypto/tls" "crypto/x509" "encoding/pem" "fmt" "log" "os" "path/filepath" "strings" "github.com/go-ldap/ldap" ) // Code relating to AD integration type LdapConfig struct { LdapBindAddress string LdapBaseDn string LdapCertFile string } var systemCA *x509.CertPool var certLoaded bool 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)) { log.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 LoadLdapCert() { var err error // Get a copy of the system defined CA's systemCA, err = x509.SystemCertPool() if err != nil { log.Printf("LoadLdapCert error getting system certificate pool : '%s'\n", err) return } // only try to load certificate from file if the command line argument was specified ldapCertFile := os.Getenv("LDAP_TRUST_CERT_FILE") if ldapCertFile == "" { log.Printf("LoadLdapCert no certificate specified\n") return } else { // Try to read the file cf, err := os.ReadFile(GetFilePath(ldapCertFile)) if err != nil { log.Printf("LoadLdapCert error opening LDAP certificate file '%s' : '%s'\n", ldapCertFile, err) return } // Get the certificate from the file cpb, _ := pem.Decode(cf) crt, err := x509.ParseCertificate(cpb.Bytes) //fmt.Printf("Loaded certificate with subject %s\n", crt.Subject) if err != nil { log.Printf("LoadLdapCert error processing LDAP certificate file '%s' : '%s'\n", ldapCertFile, err) return } // Add custom certificate to the system cert pool systemCA.AddCert(crt) certLoaded = true } } func VerifyLdapCreds(username string, password string) bool { var ldaps *ldap.Conn var err error ldapServer := os.Getenv("LDAP_BIND_ADDRESS") if ldapServer == "" { log.Printf("VerifyLdapCreds no LDAP bind address supplied\n") return false } ldapBaseDn := os.Getenv("LDAP_BASE_DN") if ldapBaseDn == "" { log.Printf("VerifyLdapCreds no LDAP base DN supplied\n") return false } // Set up TLS to use our custom certificate authority passed in cli argument tlsConfig := &tls.Config{ RootCAs: systemCA, InsecureSkipVerify: true, } // try connecting to AD via TLS and our custom certificate authority // Add port if not specified in .env file if strings.HasSuffix(ldapServer, ":636") { ldaps, err = ldap.DialTLS("tcp", ldapServer, tlsConfig) } else { ldaps, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:636", ldapServer), tlsConfig) } if err != nil { log.Printf("VerifyLdapCreds error connecting to LDAP bind address '%s' : '%s'\n", ldapServer, err) return false } defer ldaps.Close() // try to bind to AD err = ldaps.Bind(username, password) if err != nil { log.Printf("VerifyLdapCreds error binding to LDAP with supplied credentials : '%s'\n", err) return false } else { log.Printf("VerifyLdapCreds successfully bound to LDAP\n") } searchReq := ldap.NewSearchRequest( ldapBaseDn, ldap.ScopeBaseObject, // you can also use ldap.ScopeWholeSubtree ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", []string{}, nil, ) result, err := ldaps.Search(searchReq) if err != nil { log.Printf("VerifyLdapCreds search error : '%s'\n", err) return false } log.Printf("result: %v\n", result) return true }