go-ldap / ldap

Basic LDAP v3 functionality for the GO programming language.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

About Disabling Users

eryajf opened this issue · comments

When a member leaves office, how should I disable his account?

I want to disable it by pwdAccountLockedTime, only prompt when running:

LDAP Result Code 17 "Undefined Attribute Type": pwdAccountLockedTime: attribute type undefined

I suggest you opt with userAccountControl instead to disable the account:

package main

import (
	"github.com/go-ldap/ldap"
	"strconv"
)

func main() {
	// Initialize a connection and authenticate
	conn, err := ldap.Dial("tcp", "127.0.0.1:389")
	if err != nil {
		//
	}
	if err = conn.Bind("administrator@your.domain", "123456"); err != nil {
		//
	}

	// Search for the user you're looking for to obtain the distinguishedName and userAccountControl
	result, err := conn.Search(&ldap.SearchRequest{
		BaseDN:       "ou=Users,dc=your,dc=domain",
		Scope:        ldap.ScopeWholeSubtree,
		DerefAliases: ldap.NeverDerefAliases,
		Filter:       "(cn=John.Doe)",
		Attributes:   []string{"userAccountControl"},
	})
	if err != nil {
		//
	}
	if len(result.Entries) < 1 {
		// User not found
	}
	
	user := result.Entries[0]
	
	// Convert the string to a number
	uac, _ := strconv.Atoi(user.GetAttributeValues("userAccountControl")[0])
	// Set the second bit to 1 through a bitwise operation to disable the account
	// See: http://www.selfadsi.de/ads-attributes/user-userAccountControl.htm
	uac |= 2

	// Prepare a new modify request
	modifyRequest := ldap.NewModifyRequest(user.DN, nil)
	// Append the userAccountControl change and convert the number back into a string
	modifyRequest.Add("userAccountControl", []string{strconv.Itoa(uac)})
	if err = conn.Modify(modifyRequest); err != nil {
		//
	}
}

(Untested, I don't have a DS at hand :D)

GetAttributeValues("userAccountControl")

Thank you for your reply. When I GetAttributeValues("userAccountControl"), I didn't get any return. I think I need to add this attribute when creating the user, but I added this attribute when adding the user and got an error:

"Undefined Attribute Type": userAccountControl: attribute type undefined

Is there any way to add this attribute when adding users?

userAccountControl is automatically set when the user is created, otherwise the account wouldn't be able to log into machines or run bind requests against the directory server. Do you have special permissions in place which prohibit you from reading the userAccountControl attribute? Do you have it in your attribute list in your search request?

result, err := conn.Search(&ldap.SearchRequest{
		BaseDN:       "ou=Users,dc=your,dc=domain",
		Scope:        ldap.ScopeWholeSubtree,
		DerefAliases: ldap.NeverDerefAliases,
		Filter:       "(cn=John.Doe)",
		Attributes:   []string{"userAccountControl"},  # <-- this
	})

May you share some of the code for better troubleshooting?

userAccountControl is automatically set when the user is created, otherwise the account wouldn't be able to log into machines or run bind requests against the directory server. Do you have special permissions in place which prohibit you from reading the userAccountControl attribute? Do you have it in your attribute list in your search request?

result, err := conn.Search(&ldap.SearchRequest{
		BaseDN:       "ou=Users,dc=your,dc=domain",
		Scope:        ldap.ScopeWholeSubtree,
		DerefAliases: ldap.NeverDerefAliases,
		Filter:       "(cn=John.Doe)",
		Attributes:   []string{"userAccountControl"},  # <-- this
	})

May you share some of the code for better troubleshooting?

When I query a user, my code is as follows:

func SearchUser(username string) (userdn *ldap.SearchResult, err error) {
	searchRequest := ldap.NewSearchRequest(
		public.LDAP_USER_DN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", username), // The filter to apply
		[]string{},
		nil,
	)

	var sr *ldap.SearchResult
	sr, err = public.InitCli().Search(searchRequest)
	if err != nil {
		return sr, fmt.Errorf("search user failed, err: %v", err)
	}
	if len(sr.Entries) == 0 {
		return sr, errors.New("cannot find such user")
	}
	return sr, nil
}

My test code is as follows:

func TestSearchUser(t *testing.T) {
	a, err := SearchUser("aeryajf")
	if err != nil {
		fmt.Printf("user :%v\n", err)
	}
	for _, v := range a.Entries {
		fmt.Println(v.DN)
		for _, j := range v.Attributes {
			j.Print()
		}
	}
}

The results I got after running are as follows:

uid=aeryajf,ou=staff,dc=eryajf,dc=net
objectClass: [inetOrgPerson]
cn: [二丫讲梵]
sn: [aeryajf]
businessCategory: [运维部]
departmentNumber: [运维工程师]
description: [test]
displayName: [二丫讲梵]
mail: [eryajf@eryajf.net]
employeeNumber: [1]
givenName: [卧龙]
postalAddress: [this]
mobile: [15618888888]
uid: [aeryajf]
userPassword: [111111]

These results did not userAccountControl this item.

Your search request doesn't request the userAccountControl attribute from the directory server:

searchRequest := ldap.NewSearchRequest(
	public.LDAP_USER_DN,
	ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
	fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", username), // The filter to apply
	# The following was missing:
	[]string{"uid", "objectClass", "cn", "sn", "businessCategory", "departmentNumber", "description", "displayName", "mail", "employeeNumber", "givenName", "postalAddress", "mobile", "userPassword", "userAccountControl"}, 
	nil,
)
user := result.Entries[0]

when is use:

// SearchUser 查询用户
func SearchUser1(username string) (userdn *ldap.SearchResult, err error) {
	searchRequest := ldap.NewSearchRequest(
		public.LDAP_USER_DN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", username), // The filter to apply
		// []string{},
		[]string{"uid", "objectClass", "cn", "sn", "businessCategory", "departmentNumber", "description", "displayName", "mail", "employeeNumber", "givenName", "postalAddress", "mobile", "userPassword", "userAccountControl"},
		// nil,
		nil,
	)

	var sr *ldap.SearchResult
	sr, err = public.InitCli().Search(searchRequest)
	if err != nil {
		return sr, fmt.Errorf("search user failed, err: %v", err)
	}
	if len(sr.Entries) == 0 {
		return sr, errors.New("cannot find such user")
	}
	return sr, nil
}

I printed it separately and got it empty:

a, err := SearchUser1("aeryajf")
	if err != nil {
		fmt.Printf("user :%v\n", err)
	}
	
	fmt.Println(a.Entries[0].GetAttributeValues("userAccountControl"))

I got an empty array。

I don't know if I need any special configuration when deploying ldap.

The code for me to add users is as follows:

// AddUser 新增一个用户
func AddUser(u User) error {
	add := ldap.NewAddRequest(fmt.Sprintf("uid=%s,%s", u.SN, public.LDAP_USER_DN), nil)
	add.Attribute("objectClass", []string{"inetOrgPerson"})
	add.Attribute("cn", []string{u.DisplayName})
	add.Attribute("sn", []string{u.GivenName})
	add.Attribute("businessCategory", []string{u.BusinessCategory})
	add.Attribute("departmentNumber", []string{u.DepartmentNumber})
	add.Attribute("description", []string{u.Description})
	add.Attribute("displayName", []string{u.DisplayName})
	add.Attribute("mail", []string{u.Mail})
	add.Attribute("employeeNumber", []string{u.EmployeeNumber})
	add.Attribute("givenName", []string{u.GivenName})
	add.Attribute("postalAddress", []string{u.PostalAddress})
	add.Attribute("mobile", []string{u.Mobile})
	add.Attribute("uid", []string{u.UID})
	add.Attribute("userPassword", []string{u.Password})
	return public.InitCli().Add(add)
}

Just for clarification, when using ldapsearch or any LDAP browser, can you see the userAccountControl attribute with the account you're using to run the script?

Also, you're using an Active Directory, right?

Just for clarification, when using ldapsearch or any LDAP browser, can you see the userAccountControl attribute with the account you're using to run the script?

This is also not found, I did not see this attribute in the web interface.

Also, you're using an Active Directory, right?

I used the openLDAP deployed through docker and looked at the issue of the project. indeed, some people have encountered this problem. at present, I still cannot understand the ideas provided. I still need to learn

I used the openLDAP

Well this explains why you don't have the userAccountControl attribute 😅

OpenLDAP doesn't have a "defined way" to disable an account unfortunately. See https://openldap-technical.openldap.narkive.com/xA3NK3kT/enable-disable-user-account-in-openldap for more details on how others worked around this problem.

I used the openLDAP

Well this explains why you don't have the userAccountControl attribute 😅

OpenLDAP doesn't have a "defined way" to disable an account unfortunately. See openldap-technical.openldap.narkive.com/xA3NK3kT/enable-disable-user-account-in-openldap for more details on how others worked around this problem.

Thank you. I think I have already worked out a plan to deal with it.

I used the openLDAP

Well this explains why you don't have the userAccountControl attribute 😅
OpenLDAP doesn't have a "defined way" to disable an account unfortunately. See openldap-technical.openldap.narkive.com/xA3NK3kT/enable-disable-user-account-in-openldap for more details on how others worked around this problem.

Thank you. I think I have already worked out a plan to deal with it.

May you share your solutions in case others stumble upon this issue? Anyways, feel free to close this issue ^^

May you share your solutions in case others stumble upon this issue? Anyways, feel free to close this issue ^^

In fact, I am using go-ldap to write a openLDAP management background, which will be opened up after improvement. So my current idea is that when a member leaves office, he will record his status through a MySQL field and then delete it directly from the openLDAP. Maybe this is not a good solution, but at least it is feasible.

This project will be completed soon, and I will share it here at that time.