如何使用 golang 通过 TLS 绑定到 LDAP 服务器?
How to bind to LDAP server with TLS using golang?
我有以下代码,在没有 TLS/SSL 的情况下绑定到 LDAP 服务器时可以完美运行,但是当我尝试绑定到具有 TLS 设置的 LDAP 服务器时,它没有绑定。
/*In order to use this program, the user needs to get the package by running the following command:
go get gopkg.in/ldap.v2*/
package main
import (
"fmt"
"strings"
"gopkg.in/ldap.v2"
"os"
)
//Gives constants to be used for binding to and searching the LDAP server.
const (
ldapServer = "ldaps://test.com:636"
ldapBind = "CN=ad_binder,CN=Users,DC=dev,DC=test,DC=com"
ldapPassword = "Password"
filterDN = "(objectclass=*)"
baseDN = "dc=dev,dc=test,dc=com"
loginUsername = "ad_binder"
loginPassword = "Password"
)
//Main function, which is executed.
func main() {
conn, err := connect()
//If there is an error connecting to server, prints this
if err != nil {
fmt.Printf("Failed to connect. %s", err)
return
}
//Close the connection at a later time.
defer conn.Close()
//Declares err to be list(conn), and checks if any errors. It prints the error(s) if there are any.
if err := list(conn); err != nil {
fmt.Printf("%v", err)
return
}
//Declares err to be auth(conn), and checks if any errors. It prints the error(s) if there are any.
if err := auth(conn); err != nil {
fmt.Printf("%v", err)
return
}
}
//This function is used to connect to the LDAP server.
func connect() (*ldap.Conn, error) {
conn, err := ldap.Dial("tcp", ldapServer)
if err != nil {
return nil, fmt.Errorf("Failed to connect. %s", err)
}
if err := conn.Bind(ldapBind, ldapPassword); err != nil {
return nil, fmt.Errorf("Failed to bind. %s", err)
}
return conn, nil
}
//This function is used to search the LDAP server as well as output the attributes of the entries.
func list(conn *ldap.Conn) error {
//This gets the command line argument and saves it in the form "(argument=*)"
arg := ""
filter := ""
if len(os.Args) > 1{
arg = os.Args[1]
fmt.Println(arg)
filter = "(" + arg + "=*)"
} else{
fmt.Println("You need to input an argument for an attribute to search. I.E. : \"go run anonymous_query.go cn\"")
}
result, err := conn.Search(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
fmt.Sprintf(filter),
//To add anymore strings to the search, you need to add it here.
[]string{},
nil,
))
if err != nil {
return fmt.Errorf("Failed to search users. %s", err)
}
//Prints all the attributes per entry
for _, entry := range result.Entries {
entry.Print()
fmt.Println()
}
return nil
}
//This function authorizes the user and binds to the LDAP server.
func auth(conn *ldap.Conn) error {
result, err := conn.Search(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
filter(loginUsername),
[]string{"dn"},
nil,
))
if err != nil {
return fmt.Errorf("Failed to find user. %s", err)
}
if len(result.Entries) < 1 {
return fmt.Errorf("User does not exist")
}
if len(result.Entries) > 1 {
return fmt.Errorf("")
}
if err := conn.Bind(result.Entries[0].DN, loginPassword); err != nil {
fmt.Printf("Failed to auth. %s", err)
} else {
fmt.Printf("Authenticated successfuly!")
}
return nil
}
func filter(needle string) string {
res := strings.Replace(
filterDN,
"{username}",
needle,
-1,
)
return res
}
这是我尝试 运行 时遇到的错误:
Failed to connect. Failed to connect. LDAP Result Code 200 "Network Error": dial tcp: address ldaps://test.com:636: too many colons in address
这很奇怪,因为它适用于不同的 LDAP 服务器,但适用于以下内容:
ldapServer = "10.1.30.47:389"
而不是
ldapServer = "ldaps://test.com:636"
非常感谢任何帮助,谢谢!
gopkg.in/ldap.v2
不支持 URI 寻址(即不能将方案 ldap://
或 ldaps://
放在网络地址之前)。
注意:gopkg.in/ldap.v3
支持通过 DialURL.
的 URI 拨号 (ldaps://test.com
)
如果您使用gopkg.in/ldap.v2
,您仍然可以建立直接TLS连接,但您必须使用DialTLS
功能,并使用网络地址(不是URI):
// addr = "10.1.30.47:389"
// tlsAddr = "10.1.30.47:636"
// conn, err = ldap.Dial("tcp", addr) // non-TLS
// serverName = "test.com" TLS cert name will be verified
// serverName = "" TLS verify will be disabled (DON'T DO THIS IN PRODUCTION)
tlsConf, err := getTLSconfig(serverName)
if err != nil { /* */ }
conn, err = ldap.DialTLS("tcp", tlsAddr, tlsConf)
上面需要一个 *tls.Config
,所以使用像这样的辅助函数:
func getTLSconfig(tlsName string) (tlsC *tls.Config, err error) {
if tlsName != "" {
tlsC = &tls.Config{
ServerName: tlsName,
}
return
}
log.Println("No TLS verification enabled! ***STRONGLY*** recommend adding a trust file to the config.")
tlsC = &tls.Config{
InsecureSkipVerify: true,
}
return
}
我有以下代码,在没有 TLS/SSL 的情况下绑定到 LDAP 服务器时可以完美运行,但是当我尝试绑定到具有 TLS 设置的 LDAP 服务器时,它没有绑定。
/*In order to use this program, the user needs to get the package by running the following command:
go get gopkg.in/ldap.v2*/
package main
import (
"fmt"
"strings"
"gopkg.in/ldap.v2"
"os"
)
//Gives constants to be used for binding to and searching the LDAP server.
const (
ldapServer = "ldaps://test.com:636"
ldapBind = "CN=ad_binder,CN=Users,DC=dev,DC=test,DC=com"
ldapPassword = "Password"
filterDN = "(objectclass=*)"
baseDN = "dc=dev,dc=test,dc=com"
loginUsername = "ad_binder"
loginPassword = "Password"
)
//Main function, which is executed.
func main() {
conn, err := connect()
//If there is an error connecting to server, prints this
if err != nil {
fmt.Printf("Failed to connect. %s", err)
return
}
//Close the connection at a later time.
defer conn.Close()
//Declares err to be list(conn), and checks if any errors. It prints the error(s) if there are any.
if err := list(conn); err != nil {
fmt.Printf("%v", err)
return
}
//Declares err to be auth(conn), and checks if any errors. It prints the error(s) if there are any.
if err := auth(conn); err != nil {
fmt.Printf("%v", err)
return
}
}
//This function is used to connect to the LDAP server.
func connect() (*ldap.Conn, error) {
conn, err := ldap.Dial("tcp", ldapServer)
if err != nil {
return nil, fmt.Errorf("Failed to connect. %s", err)
}
if err := conn.Bind(ldapBind, ldapPassword); err != nil {
return nil, fmt.Errorf("Failed to bind. %s", err)
}
return conn, nil
}
//This function is used to search the LDAP server as well as output the attributes of the entries.
func list(conn *ldap.Conn) error {
//This gets the command line argument and saves it in the form "(argument=*)"
arg := ""
filter := ""
if len(os.Args) > 1{
arg = os.Args[1]
fmt.Println(arg)
filter = "(" + arg + "=*)"
} else{
fmt.Println("You need to input an argument for an attribute to search. I.E. : \"go run anonymous_query.go cn\"")
}
result, err := conn.Search(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
fmt.Sprintf(filter),
//To add anymore strings to the search, you need to add it here.
[]string{},
nil,
))
if err != nil {
return fmt.Errorf("Failed to search users. %s", err)
}
//Prints all the attributes per entry
for _, entry := range result.Entries {
entry.Print()
fmt.Println()
}
return nil
}
//This function authorizes the user and binds to the LDAP server.
func auth(conn *ldap.Conn) error {
result, err := conn.Search(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
filter(loginUsername),
[]string{"dn"},
nil,
))
if err != nil {
return fmt.Errorf("Failed to find user. %s", err)
}
if len(result.Entries) < 1 {
return fmt.Errorf("User does not exist")
}
if len(result.Entries) > 1 {
return fmt.Errorf("")
}
if err := conn.Bind(result.Entries[0].DN, loginPassword); err != nil {
fmt.Printf("Failed to auth. %s", err)
} else {
fmt.Printf("Authenticated successfuly!")
}
return nil
}
func filter(needle string) string {
res := strings.Replace(
filterDN,
"{username}",
needle,
-1,
)
return res
}
这是我尝试 运行 时遇到的错误:
Failed to connect. Failed to connect. LDAP Result Code 200 "Network Error": dial tcp: address ldaps://test.com:636: too many colons in address
这很奇怪,因为它适用于不同的 LDAP 服务器,但适用于以下内容:
ldapServer = "10.1.30.47:389"
而不是
ldapServer = "ldaps://test.com:636"
非常感谢任何帮助,谢谢!
gopkg.in/ldap.v2
不支持 URI 寻址(即不能将方案 ldap://
或 ldaps://
放在网络地址之前)。
注意:gopkg.in/ldap.v3
支持通过 DialURL.
ldaps://test.com
)
如果您使用gopkg.in/ldap.v2
,您仍然可以建立直接TLS连接,但您必须使用DialTLS
功能,并使用网络地址(不是URI):
// addr = "10.1.30.47:389"
// tlsAddr = "10.1.30.47:636"
// conn, err = ldap.Dial("tcp", addr) // non-TLS
// serverName = "test.com" TLS cert name will be verified
// serverName = "" TLS verify will be disabled (DON'T DO THIS IN PRODUCTION)
tlsConf, err := getTLSconfig(serverName)
if err != nil { /* */ }
conn, err = ldap.DialTLS("tcp", tlsAddr, tlsConf)
上面需要一个 *tls.Config
,所以使用像这样的辅助函数:
func getTLSconfig(tlsName string) (tlsC *tls.Config, err error) {
if tlsName != "" {
tlsC = &tls.Config{
ServerName: tlsName,
}
return
}
log.Println("No TLS verification enabled! ***STRONGLY*** recommend adding a trust file to the config.")
tlsC = &tls.Config{
InsecureSkipVerify: true,
}
return
}