initial work on adding LDAP integration
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
146
models/ldap.go
Normal file
146
models/ldap.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"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)) {
|
||||
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 LoadLdapCert() {
|
||||
var err error
|
||||
// Get a copy of the system defined CA's
|
||||
systemCA, err = x509.SystemCertPool()
|
||||
if err != nil {
|
||||
fmt.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 != "" {
|
||||
// Try to read the file
|
||||
cf, err := os.ReadFile(GetFilePath(ldapCertFile))
|
||||
if err != nil {
|
||||
fmt.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 {
|
||||
fmt.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 == "" {
|
||||
fmt.Printf("VerifyLdapCreds no LDAP bind address supplied\n")
|
||||
return false
|
||||
}
|
||||
|
||||
ldapBaseDn := os.Getenv("LDAP_BASE_DN")
|
||||
if ldapBaseDn == "" {
|
||||
fmt.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 {
|
||||
fmt.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 {
|
||||
fmt.Printf("VerifyLdapCreds error binding to LDAP with supplied credentials : '%s'\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
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 {
|
||||
fmt.Printf("VerifyLdapCreds search error : '%s'\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
fmt.Printf("result: %v\n", result)
|
||||
|
||||
return true
|
||||
}
|
@@ -88,12 +88,15 @@ func LoginCheck(username string, password string) (string, error) {
|
||||
// Query database for matching user object
|
||||
err = db.QueryRowx("SELECT * FROM Users WHERE Username=?", username).StructScan(&u)
|
||||
|
||||
log.Printf("LoginCheck retrieved user '%v' from database\n", u)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
log.Printf("LoginCheck retrieved user '%v' from database\n", u)
|
||||
}
|
||||
|
||||
// TODO : attempt ldap bind
|
||||
VerifyLdapCreds(username, password)
|
||||
|
||||
err = VerifyPassword(password, u.Password)
|
||||
|
||||
if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
|
||||
|
Reference in New Issue
Block a user