2020-09-17 16:20:04 -04:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
2020-09-24 16:14:54 -04:00
|
|
|
"strconv"
|
2021-03-31 16:12:35 -04:00
|
|
|
"strings"
|
2020-09-17 16:20:04 -04:00
|
|
|
|
|
|
|
"github.com/go-ldap/ldap"
|
|
|
|
)
|
|
|
|
|
2020-11-10 17:58:24 -05:00
|
|
|
func createLDAPMCAccount(uname, mcuname string) error {
|
|
|
|
if uname == "" || mcuname == "" {
|
|
|
|
log.Printf("error: missing field\n")
|
|
|
|
return errors.New("Missing field")
|
|
|
|
}
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
newdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, mcuname, Conf.Ldap.MineUserOu, Conf.Ldap.LdapDc)
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
maindn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, uname, Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
addReq := ldap.NewAddRequest(newdn, []ldap.Control{})
|
|
|
|
addReq.Attribute("objectClass", []string{"top", "account"})
|
|
|
|
addReq.Attribute("seeAlso", []string{maindn})
|
|
|
|
if err := l.Add(addReq); err != nil {
|
2021-10-15 11:34:27 -04:00
|
|
|
log.Printf("error adding service:%v %v", addReq, err)
|
2020-11-10 17:58:24 -05:00
|
|
|
return errors.New("Error creating LDAP account")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-17 16:20:04 -04:00
|
|
|
func createLDAPAccount(uname string, pwd string, email string) error {
|
2020-09-17 19:53:02 -04:00
|
|
|
if uname == "" || pwd == "" || email == "" {
|
2021-10-15 11:34:27 -04:00
|
|
|
log.Println("error: missing field")
|
2020-09-17 19:53:02 -04:00
|
|
|
return errors.New("Missing field")
|
|
|
|
}
|
2020-09-17 16:20:04 -04:00
|
|
|
url := Conf.Ldap.Url
|
|
|
|
newdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, uname, Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
addReq := ldap.NewAddRequest(newdn, []ldap.Control{})
|
|
|
|
addReq.Attribute("objectClass", []string{"top", "person", "organizationalPerson", "inetOrgPerson"})
|
|
|
|
addReq.Attribute("cn", []string{uname})
|
|
|
|
addReq.Attribute("mail", []string{email})
|
|
|
|
addReq.Attribute("sn", []string{"The Nameless"})
|
2020-09-24 16:14:54 -04:00
|
|
|
addReq.Attribute("givenName", []string{uname})
|
|
|
|
addReq.Attribute("employeeType", []string{"default"})
|
|
|
|
addReq.Attribute("employeeNumber", []string{strconv.Itoa(getNextId())})
|
|
|
|
addReq.Attribute("displayName", []string{uname})
|
2020-09-17 16:20:04 -04:00
|
|
|
|
|
|
|
if err := l.Add(addReq); err != nil {
|
2021-10-15 11:34:27 -04:00
|
|
|
log.Printf("error adding service: %v %v", addReq, err)
|
2020-09-17 16:20:04 -04:00
|
|
|
return errors.New("Error creating LDAP account")
|
|
|
|
}
|
|
|
|
|
|
|
|
passwordModifyRequest := ldap.NewPasswordModifyRequest(newdn, "", pwd)
|
|
|
|
_, err = l.PasswordModify(passwordModifyRequest)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Password could not be changed: %s", err.Error())
|
|
|
|
return errors.New("Error setting password")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func loginLDAPAccount(uname string, pwd string) error {
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
userdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, uname, Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
2020-09-22 14:00:28 -04:00
|
|
|
fmt.Sprintf("(&(objectClass=organizationalPerson)(%s=%s))", Conf.Ldap.UserAttr, uname),
|
2020-09-17 16:20:04 -04:00
|
|
|
[]string{"dn"},
|
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
|
|
err_text := fmt.Sprintf("Error finding login user: Wanted 1 result, got %v\n", len(result.Entries))
|
|
|
|
return errors.New(err_text)
|
|
|
|
}
|
|
|
|
err = l.Bind(userdn, pwd)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-09-22 18:21:01 -04:00
|
|
|
|
2023-04-10 17:51:49 -04:00
|
|
|
func resetLDAPAccountPassword(user string, oldPass, newPass string) error {
|
2020-09-22 18:21:01 -04:00
|
|
|
url := Conf.Ldap.Url
|
|
|
|
userdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, user, Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
fmt.Sprintf("(&(objectClass=organizationalPerson)(%s=%s))", Conf.Ldap.UserAttr, user),
|
|
|
|
[]string{"dn"},
|
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
|
|
err_text := fmt.Sprintf("Error finding login user: Wanted 1 result, got %v\n", len(result.Entries))
|
|
|
|
return errors.New(err_text)
|
|
|
|
}
|
2023-04-10 17:51:49 -04:00
|
|
|
passwordModifyRequest := ldap.NewPasswordModifyRequest(userdn, oldPass, newPass)
|
2020-09-22 18:21:01 -04:00
|
|
|
_, err = l.PasswordModify(passwordModifyRequest)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Password could not be changed: %s", err.Error())
|
|
|
|
return errors.New("Error setting password")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func findLDAPAccountByEmail(email string) (string, error) {
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
fmt.Sprintf("(&(objectClass=organizationalPerson)(mail=%s))", email),
|
|
|
|
[]string{"dn", Conf.Ldap.UserAttr},
|
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
|
|
err_text := fmt.Sprintf("Error finding user: Wanted 1 result, got %v\n", len(result.Entries))
|
|
|
|
return "", errors.New(err_text)
|
|
|
|
}
|
|
|
|
entry := result.Entries[0]
|
|
|
|
|
|
|
|
return entry.GetAttributeValue(Conf.Ldap.UserAttr), nil
|
|
|
|
}
|
2020-11-10 17:58:24 -05:00
|
|
|
func findLDAPMCAccount(uname string) (string, error) {
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.MineUserOu, Conf.Ldap.LdapDc)
|
|
|
|
userdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, uname, Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
fmt.Sprintf("(&(objectClass=account)(seeAlso=%s))", userdn),
|
|
|
|
[]string{"uid"},
|
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
|
|
err_text := fmt.Sprintf("Error finding user: Wanted 1 result, got %v\n", len(result.Entries))
|
|
|
|
return "", errors.New(err_text)
|
|
|
|
}
|
|
|
|
entry := result.Entries[0]
|
|
|
|
return entry.GetAttributeValue("uid"), nil
|
|
|
|
}
|
2020-09-24 16:39:52 -04:00
|
|
|
func findLDAPAccountForDisplay(uname string) (User, error) {
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return User{}, err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return User{}, err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
fmt.Sprintf("(&(objectClass=organizationalPerson)(%s=%s))", Conf.Ldap.UserAttr, uname),
|
2021-03-31 16:12:35 -04:00
|
|
|
[]string{"cn", "sn", "givenName", "displayName", "mail", "employeeNumber", "memberOf"},
|
2020-09-24 16:39:52 -04:00
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return User{}, err
|
|
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
|
|
err_text := fmt.Sprintf("Error finding user: Wanted 1 result, got %v\n", len(result.Entries))
|
|
|
|
return User{}, errors.New(err_text)
|
|
|
|
}
|
|
|
|
entry := result.Entries[0]
|
2021-03-31 16:12:35 -04:00
|
|
|
groups := entry.GetAttributeValues("memberOf")
|
|
|
|
fg := make([]string, 0)
|
|
|
|
for _, group := range groups {
|
|
|
|
group_s := strings.Split(group, ",")
|
|
|
|
group_cn := group_s[0]
|
|
|
|
fg = append(fg, strings.Trim(group_cn, "cn="))
|
|
|
|
}
|
|
|
|
|
2020-09-24 16:39:52 -04:00
|
|
|
u := User{
|
2021-03-31 16:12:35 -04:00
|
|
|
Username: entry.GetAttributeValue("cn"),
|
|
|
|
FirstName: entry.GetAttributeValue("givenName"),
|
|
|
|
LastName: entry.GetAttributeValue("sn"),
|
|
|
|
DisplayName: entry.GetAttributeValue("displayName"),
|
|
|
|
Email: entry.GetAttributeValue("mail"),
|
|
|
|
ID: entry.GetAttributeValue("employeeNumber"),
|
|
|
|
Groups: groups,
|
|
|
|
FriendlyGroups: fg,
|
2020-09-24 16:39:52 -04:00
|
|
|
}
|
|
|
|
return u, nil
|
2020-09-24 17:12:22 -04:00
|
|
|
}
|
|
|
|
func updateLDAPAccountByUser(user User) error {
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
userdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, user.Username, Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
fmt.Sprintf("(&(objectClass=organizationalPerson)(%s=%s))", Conf.Ldap.UserAttr, user.Username),
|
|
|
|
[]string{"dn"},
|
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(result.Entries) != 1 {
|
|
|
|
err_text := fmt.Sprintf("Error finding login user: Wanted 1 result, got %v\n", len(result.Entries))
|
|
|
|
return errors.New(err_text)
|
|
|
|
}
|
|
|
|
modify := ldap.NewModifyRequest(userdn, nil)
|
|
|
|
modify.Replace("mail", []string{user.Email})
|
|
|
|
modify.Replace("givenName", []string{user.FirstName})
|
|
|
|
modify.Replace("sn", []string{user.LastName})
|
|
|
|
modify.Replace("displayName", []string{user.DisplayName})
|
|
|
|
err = l.Modify(modify)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2020-09-24 16:39:52 -04:00
|
|
|
}
|
2020-09-24 16:14:54 -04:00
|
|
|
func findLDAPMaxID() (int, error) {
|
|
|
|
url := Conf.Ldap.Url
|
|
|
|
binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc)
|
|
|
|
basedn := fmt.Sprintf("%v,%v", Conf.Ldap.UserOu, Conf.Ldap.LdapDc)
|
|
|
|
|
|
|
|
l, err := ldap.DialURL(url)
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
err = l.Bind(binddn, Conf.Ldap.LdapPass)
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
result, err := l.Search(ldap.NewSearchRequest(
|
|
|
|
basedn,
|
|
|
|
ldap.ScopeWholeSubtree,
|
|
|
|
ldap.NeverDerefAliases,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
false,
|
|
|
|
fmt.Sprintf("(&(objectClass=organizationalPerson)(employeeNumber=*))"),
|
|
|
|
[]string{"employeeNumber"},
|
|
|
|
nil,
|
|
|
|
))
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
maxId := 0
|
|
|
|
for _, entry := range result.Entries {
|
|
|
|
i, err := strconv.Atoi(entry.GetAttributeValue("employeeNumber"))
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
if i > maxId {
|
|
|
|
maxId = i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return maxId + 1, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func getNextId() int {
|
|
|
|
if Conf.MaxID == 0 {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
Conf.lock.Lock()
|
|
|
|
i := Conf.MaxID
|
|
|
|
Conf.MaxID = Conf.MaxID + 1
|
|
|
|
Conf.lock.Unlock()
|
|
|
|
return i
|
|
|
|
}
|