Files
smt/models/ldap.go
Nathan Coad 55f7bacd7b
All checks were successful
continuous-integration/drone/push Build is passing
test again
2024-01-04 12:23:08 +11:00

153 lines
3.6 KiB
Go

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,
}
// Add port if not specified in .env file
if !(strings.HasSuffix(ldapServer, ":636")) {
ldapServer = fmt.Sprintf("%s:636", ldapServer)
log.Printf("VerifyLdapCreds updated ldapServer string '%s'\n", ldapServer)
}
// try connecting to AD via TLS and our custom certificate authority
ldaps, err = ldap.DialTLS("tcp", 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
}