Как привязаться к серверу LDAP с помощью TLS с помощью golang?

#go #active-directory #ldap

#Вперед #active-directory #ldap

Вопрос:

У меня есть следующий код, который отлично работает при привязке к серверу LDAP без TLS / SSL, но когда я пытаюсь привязаться к серверу LDAP, на котором настроен TLS, он не привязывается.

 

/*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"
  

Так что любая помощь будет с благодарностью принята, спасибо!

Ответ №1:

gopkg.in/ldap.v2 не поддерживает адресацию URI (т. Е. Вы не можете поместить схему ldap:// или ldaps:// перед сетевым адресом).

Примечание: gopkg.in/ldap.v3 поддерживает набор URI ( ldaps://test.com ) через DialURL.

Если вы используете 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 = amp;tls.Config{
            ServerName: tlsName,
        }
        return
    }

    log.Println("No TLS verification enabled! ***STRONGLY*** recommend adding a trust file to the config.")
    tlsC = amp;tls.Config{
        InsecureSkipVerify: true,
    }
    return
}