more work on 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:
6
main.go
6
main.go
@@ -147,12 +147,10 @@ func main() {
|
|||||||
models.ReceiveKey(keyString)
|
models.ReceiveKey(keyString)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load certificate for LDAP connectivy
|
// If LDAP configuration is defined, prepare connection
|
||||||
models.LoadLdapCert()
|
|
||||||
|
|
||||||
ldapServer := os.Getenv("LDAP_BIND_ADDRESS")
|
ldapServer := os.Getenv("LDAP_BIND_ADDRESS")
|
||||||
if ldapServer != "" {
|
if ldapServer != "" {
|
||||||
models.LdapEnabled = true
|
models.LdapSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create context that listens for the interrupt signal from the OS.
|
// Create context that listens for the interrupt signal from the OS.
|
||||||
|
104
models/ldap.go
104
models/ldap.go
@@ -22,8 +22,10 @@ type LdapConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var systemCA *x509.CertPool
|
var systemCA *x509.CertPool
|
||||||
|
var ldaps *ldap.Conn
|
||||||
var CertLoaded bool
|
var CertLoaded bool
|
||||||
var LdapEnabled bool
|
var LdapEnabled bool
|
||||||
|
var LdapBaseDn string
|
||||||
|
|
||||||
func GetFilePath(path string) string {
|
func GetFilePath(path string) string {
|
||||||
// Check for empty filename
|
// Check for empty filename
|
||||||
@@ -46,7 +48,7 @@ func GetFilePath(path string) string {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadLdapCert() {
|
func loadLdapCert() {
|
||||||
var err error
|
var err error
|
||||||
// Get a copy of the system defined CA's
|
// Get a copy of the system defined CA's
|
||||||
systemCA, err = x509.SystemCertPool()
|
systemCA, err = x509.SystemCertPool()
|
||||||
@@ -85,9 +87,12 @@ func LoadLdapCert() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyLdapCreds(username string, password string) bool {
|
func LdapSetup() bool {
|
||||||
var ldaps *ldap.Conn
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
// Load LDAP certificate if necessary
|
||||||
|
loadLdapCert()
|
||||||
|
|
||||||
ldapServer := os.Getenv("LDAP_BIND_ADDRESS")
|
ldapServer := os.Getenv("LDAP_BIND_ADDRESS")
|
||||||
if ldapServer == "" {
|
if ldapServer == "" {
|
||||||
log.Printf("VerifyLdapCreds no LDAP bind address supplied\n")
|
log.Printf("VerifyLdapCreds no LDAP bind address supplied\n")
|
||||||
@@ -96,8 +101,8 @@ func VerifyLdapCreds(username string, password string) bool {
|
|||||||
LdapEnabled = true
|
LdapEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
ldapBaseDn := os.Getenv("LDAP_BASE_DN")
|
LdapBaseDn = os.Getenv("LDAP_BASE_DN")
|
||||||
if ldapBaseDn == "" {
|
if LdapBaseDn == "" {
|
||||||
log.Printf("VerifyLdapCreds no LDAP base DN supplied\n")
|
log.Printf("VerifyLdapCreds no LDAP base DN supplied\n")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -123,10 +128,48 @@ func VerifyLdapCreds(username string, password string) bool {
|
|||||||
|
|
||||||
defer ldaps.Close()
|
defer ldaps.Close()
|
||||||
|
|
||||||
//ldaps.Debug = true
|
LdapEnabled = true
|
||||||
|
|
||||||
// try to bind to AD
|
LookupNamingContext()
|
||||||
log.Printf("Attempting LDAP bind with user '%s' and password '%s'\n", username, password)
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func LookupNamingContext() {
|
||||||
|
// Retrieve the defaultNamingContext
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
"",
|
||||||
|
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
"(objectClass=*)",
|
||||||
|
[]string{"defaultNamingContext"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
searchResult, err := ldaps.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("LookupNamingContext unable to perform unauthenticated search : '%s'\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(searchResult.Entries) != 1 {
|
||||||
|
log.Printf("LookupNamingContext unable to retrieve defaultNamingContext\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultNamingContext := searchResult.Entries[0].GetAttributeValue("defaultNamingContext")
|
||||||
|
if defaultNamingContext == "" {
|
||||||
|
log.Printf("LookupNamingContext defaultNamingContext attribute not found\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Default Naming Context: '%s'\n", defaultNamingContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyLdapCreds(username string, password string) bool {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// try an authenticated bind to AD to verify credentials
|
||||||
|
log.Printf("Attempting LDAP bind with user '%s' and password length '%d'\n", username, len(password))
|
||||||
err = ldaps.Bind(username, password)
|
err = ldaps.Bind(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ldapErr, ok := err.(*ldap.Error); ok && ldapErr.ResultCode == ldap.LDAPResultInvalidCredentials {
|
if ldapErr, ok := err.(*ldap.Error); ok && ldapErr.ResultCode == ldap.LDAPResultInvalidCredentials {
|
||||||
@@ -140,9 +183,9 @@ func VerifyLdapCreds(username string, password string) bool {
|
|||||||
log.Printf("VerifyLdapCreds successfully bound to LDAP\n")
|
log.Printf("VerifyLdapCreds successfully bound to LDAP\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Attempting LDAP search request from base DN '%s'\n", ldapBaseDn)
|
log.Printf("Attempting LDAP search request from base DN '%s'\n", LdapBaseDn)
|
||||||
searchReq := ldap.NewSearchRequest(
|
searchReq := ldap.NewSearchRequest(
|
||||||
ldapBaseDn,
|
LdapBaseDn,
|
||||||
ldap.ScopeWholeSubtree, // you can also use ldap.ScopeWholeSubtree
|
ldap.ScopeWholeSubtree, // you can also use ldap.ScopeWholeSubtree
|
||||||
ldap.NeverDerefAliases,
|
ldap.NeverDerefAliases,
|
||||||
0,
|
0,
|
||||||
@@ -162,3 +205,44 @@ func VerifyLdapCreds(username string, password string) bool {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGroupsOfUser returns the group for a user.
|
||||||
|
// Taken from https://github.com/jtblin/go-ldap-client/issues/13#issuecomment-456090979
|
||||||
|
func GetGroupsOfUser(username string, baseDN string, conn *ldap.Conn) ([]string, error) {
|
||||||
|
var samAccountName string
|
||||||
|
var groups []string
|
||||||
|
|
||||||
|
if strings.Contains(username, "@") {
|
||||||
|
s := strings.Split(username, "@")
|
||||||
|
samAccountName = s[0]
|
||||||
|
} else if strings.Contains(username, "\\") {
|
||||||
|
s := strings.Split(username, "\\")
|
||||||
|
samAccountName = s[len(s)-1]
|
||||||
|
} else {
|
||||||
|
samAccountName = username
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the users DN
|
||||||
|
// Search for the given username
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(samAccountName)),
|
||||||
|
[]string{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
sr, err := conn.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sr.Entries) != 1 {
|
||||||
|
return nil, fmt.Errorf("user '%s' does not exist", samAccountName)
|
||||||
|
} else {
|
||||||
|
// Get the groups of the first result
|
||||||
|
groups = sr.Entries[0].GetAttributeValues("memberOf")
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user