Mastering Go-LDAP: Connect, Manage, and Secure LDAP with Go
Learn how to use the Go‑ldap library to connect to an LDAP server, set up a Docker‑based LDAP environment, and perform core operations such as creating, listing, deleting users and checking weak passwords, complete with full code examples and optimization tips.
1 Go Connect LDAP Service
Use the go-ldap package, which implements LDAP v3 functions such as connecting, adding, deleting, and modifying user entries, and supports conditional searches.
2 Download
<code>go get github.com/go-ldap/ldap/v3
go get github.com/wxnacy/wgo/arrays</code>Documentation can be found at gopkg.in/[email protected]#section-readme.
3 Prepare LDAP Environment
Run a temporary LDAP instance with docker‑compose:
<code>version: "3"
services:
ldap:
image: osixia/openldap:latest
container_name: openldap
hostname: openldap
restart: always
environment:
- "LDAP_ORGANISATION=devopsman"
- "LDAP_DOMAIN=devopsman.cn"
- "LDAP_BASE_DN=dc=devopsman,dc=cn"
- "LDAP_ADMIN_PASSWORD=admin123"
ports:
- 389:389
- 636:636
</code>Modify environment variables as needed. The image can be found on hub.docker.com.
4 GO‑LDAP Example
Create User
Use Add and NewAddRequest to create a user. First bind to the server with an account that has creation rights.
<code>// LoginBind connection ldap server and binding ldap server
func LoginBind(ldapUser, ldapPassword string) (*ldap.Conn, error) {
l, err := ldap.DialURL(ldapURL)
if err != nil {
return nil, err
}
_, err = l.SimpleBind(&ldap.SimpleBindRequest{
Username: fmt.Sprintf("cn=%s,dc=devopsman,dc=cn", ldapUser),
Password: ldapPassword,
})
if err != nil {
fmt.Println("ldap password is error: ", ldap.LDAPResultInvalidCredentials)
return nil, err
}
fmt.Println(ldapUser, "登录成功")
return l, nil
}
</code>Define a User struct with required fields.
<code>type User struct {
username string
password string
telephone string
emailSuffix string
snUsername string
uid string
gid string
}
</code>Implement addUser using NewAddRequest.
<code>func (user *User) addUser(conn *ldap.Conn) error {
ldaprow := ldap.NewAddRequest(fmt.Sprintf("cn=%s,dc=devopsman,dc=cn", user.username), nil)
ldaprow.Attribute("userPassword", []string{user.password})
ldaprow.Attribute("homeDirectory", []string{fmt.Sprintf("/home/%s", user.username)})
ldaprow.Attribute("cn", []string{user.username})
ldaprow.Attribute("uid", []string{user.username})
ldaprow.Attribute("objectClass", []string{"shadowAccount", "posixAccount", "account"})
ldaprow.Attribute("uidNumber", []string{"2201"})
ldaprow.Attribute("gidNumber", []string{"2201"})
ldaprow.Attribute("loginShell", []string{"/bin/bash"})
if err := conn.Add(ldaprow); err != nil {
return err
}
return nil
}
</code>Instantiate User and call addUser.
<code>func main() {
con, err := LoginBind("admin", "admin123")
fmt.Println(con.IsClosing())
if err != nil {
fmt.Println("V")
fmt.Println(err)
}
var user User
user.username = "marionxue"
user.password = "admin123"
user.snUsername = "Marionxue"
user.uid = "1000"
user.gid = "1000"
user.emailSuffix = "@qq.com"
if err = user.addUser(con); err != nil {
fmt.Println(err)
}
fmt.Println(user.username, "创建完成!")
}
</code>Running the program creates the user.
List Users
Reuse LoginBind and implement GetEmployees to search the directory.
<code>func GetEmployees(con *ldap.Conn) ([]string, error) {
var employees []string
sql := ldap.NewSearchRequest(
"dc=devopsman,dc=cn",
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(objectClass=*)",
[]string{"dn", "cn", "objectClass"},
nil,
)
cur, err := con.Search(sql)
if err != nil {
return nil, err
}
if len(cur.Entries) > 0 {
for _, item := range cur.Entries {
cn := item.GetAttributeValues("cn")
for _, iCn := range cn {
employees = append(employees, strings.Split(iCn, "[")[0])
}
}
return employees, nil
}
return nil, nil
}
</code>Print the retrieved usernames.
<code>func main() {
con, err := LoginBind("admin", "admin123")
if err != nil {
fmt.Println("V")
fmt.Println(err)
}
employees, err := GetEmployees(con)
if err != nil {
fmt.Println(err)
}
for _, employe := range employees {
fmt.Println(employe)
}
}
</code>Delete User
Implement delUser using NewDelRequest.
<code>// delUser 删除用户
func (user *User) delUser(conn *ldap.Conn) error {
ldaprow := ldap.NewDelRequest(fmt.Sprintf("cn=%s,dc=devopsman,dc=cn", user.username), nil)
if err := conn.Del(ldaprow); err != nil {
return err
}
return nil
}
</code>Call delUser in main after binding.
<code>func main() {
con, err := LoginBind("admin", "admin123")
if err != nil {
fmt.Println("V")
fmt.Println(err)
}
var user User
user.username = "marionxue"
if err := user.delUser(con); err != nil {
fmt.Println("用户删除失败")
}
fmt.Println(user.username, "用户删除成功!")
}
</code>Weak Password Check
Because LDAP does not store passwords in plain text, a dictionary‑based login attempt can identify weak passwords.
<code>func CheckPassword(employe string) {
// 遍历的弱密码字典
f, err := os.Open("~/dict.txt")
if err != nil {
fmt.Println("reading dict.txt error: ", err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
weakpassword := scanner.Text()
_, err := LoginBind(employe, weakpassword)
if err == nil {
fmt.Println(employe + " 使用的密码为: " + weakpassword)
}
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
}
fmt.Println(employe + " check have already finished. and the password is stronger well.")
}
</code>Combine enumeration and checking, skipping whitelisted accounts.
<code>func main() {
con, err := LoginBind("admin", "admin123")
if err != nil {
fmt.Println("V")
fmt.Println(err)
}
employees, err := GetEmployees(con)
if err != nil {
fmt.Println(err)
}
Whitelist := []string{"zhangsan", "lisi"}
for _, employe := range employees {
fmt.Println("Starting check: ", employe)
if index := arrays.ContainsString(Whitelist, employe); index == -1 {
CheckPassword(employe)
} else {
fmt.Println(employe + " in whitelist. skiping...")
}
}
}
</code>Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.