LDAP Authentication in Golang with Bind and Search

If you are familiar with the Windows Active Directory or Samba, you may have already heard about LDAP. But if you didn’t, here is the description in Wikipedia.

Lightweight Directory Access Protocol (LDAP) is an open, vendor-neutral, industry standard…


This content originally appeared on DEV Community and was authored by Rıdvan Tülemen

If you are familiar with the Windows Active Directory or Samba, you may have already heard about LDAP. But if you didn't, here is the description in Wikipedia.

Lightweight Directory Access Protocol (LDAP) is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over an Internet Protocol (IP) network.

Creating our project

First of all, we need to download the library:

go get github.com/go-ldap/ldap

Variables

Now, we can start using the library. Firstly, we are creating the variables to use them later(If you are going to use anonymous bind, you only need Filter):

const (
    BindUsername = "user@example.com"
    BindPassword = "password"
    FQDN         = "DC.example.com"
    BaseDN       = "cn=Configuration,dc=example,dc=com"
    Filter       = "(objectClass=*)"
)

Connect

To connect to LDAP, we can use ldap.DialURL() func. Followed function is solely created to connect to an LDAP server:

// Ldap Connection without TLS
func Connect() (*ldap.Conn, error) {
    // You can also use IP instead of FQDN
    l, err := ldap.DialURL(fmt.Sprintf("ldap://%s:389", FQDN))
    if err != nil {
        return nil, err
    }

    return l, nil
}

TLS Connect

If you need TLS Connection, you can use the function below:

// Ldap Connection with TLS
func ConnectTLS() (*ldap.Conn, error) {
    // You can also use IP instead of FQDN
    l, err := ldap.DialURL(fmt.Sprintf("ldaps://%s:636", FQDN))
    if err != nil {
        return nil, err
    }

    return l, nil
}

Anonymous Bind and Search

If you want anonymous bind in your project, you can use this function:

// Anonymous Bind and Search
func AnonymousBindAndSearch(l *ldap.Conn) (*ldap.SearchResult, error) {
    l.UnauthenticatedBind("")

    anonReq := ldap.NewSearchRequest(
        "",
        ldap.ScopeBaseObject, // you can also use ldap.ScopeWholeSubtree
        ldap.NeverDerefAliases,
        0,
        0,
        false,
        Filter,
        []string{},
        nil,
    )
    result, err := l.Search(anonReq)
    if err != nil {
        return nil, fmt.Errorf("Anonymous Bind Search Error: %s", err)
    }

    if len(result.Entries) > 0 {
        result.Entries[0].Print()
        return result, nil
    } else {
        return nil, fmt.Errorf("Couldn't fetch anonymous bind search entries")
    }
}

Bind and Search

If you prefer normal binding instead:

// Normal Bind and Search
func BindAndSearch(l *ldap.Conn) (*ldap.SearchResult, error) {
    l.Bind(BindUsername, BindPassword)

    searchReq := ldap.NewSearchRequest(
        BaseDN,
        ldap.ScopeBaseObject, // you can also use ldap.ScopeWholeSubtree
        ldap.NeverDerefAliases,
        0,
        0,
        false,
        Filter,
        []string{},
        nil,
    )
    result, err := l.Search(searchReq)
    if err != nil {
        return nil, fmt.Errorf("Search Error: %s", err)
    }

    if len(result.Entries) > 0 {
        return result, nil
    } else {
        return nil, fmt.Errorf("Couldn't fetch search entries")
    }
}

Main Func

Last of all, we need to create a main function to use these functions:

Bind and Search with TLS Connection

func main() {
    // TLS Connection
    l, err := ConnectTLS()
    if err != nil {
        log.Fatal(err)
    }
    defer l.Close()

    // Normal Bind and Search
    result, err = BindAndSearch(l)
    if err != nil {
        log.Fatal(err)
    }
    result.Entries[0].Print()
}

Anonymous Bind and Search with Non-TLS Connection

func main() {
    // Non-TLS Connection
    l, err := Connect()
    if err != nil {
        log.Fatal(err)
    }
    defer l.Close()

    // Anonymous Bind and Search
    result, err := AnonymousBindAndSearch(l)
    if err != nil {
        log.Fatal(err)
    }
    result.Entries[0].Print()
}

Conclusion

After these functions, I believe you can start using LDAP authentication, bind and search. At the end, the code should look like this:

package main

import (
    "fmt"
    "log"

    "github.com/go-ldap/ldap/v3"
)

const (
    BindUsername = "user@example.com"
    BindPassword = "password"
    FQDN         = "DC.example.com"
    BaseDN       = "cn=Configuration,dc=example,dc=com"
    Filter       = "(objectClass=*)"
)

func main() {
    // TLS Connection
    l, err := ConnectTLS()
    if err != nil {
        log.Fatal(err)
    }
    defer l.Close()

    // Non-TLS Connection
    //l, err := Connect()
    //if err != nil {
    //  log.Fatal(err)
    //}
    //defer l.Close()

    // Anonymous Bind and Search
    result, err := AnonymousBindAndSearch(l)
    if err != nil {
        log.Fatal(err)
    }
    result.Entries[0].Print()

    // Normal Bind and Search
    result, err = BindAndSearch(l)
    if err != nil {
        log.Fatal(err)
    }
    result.Entries[0].Print()
}

// Ldap Connection with TLS
func ConnectTLS() (*ldap.Conn, error) {
    // You can also use IP instead of FQDN
    l, err := ldap.DialURL(fmt.Sprintf("ldaps://%s:636", FQDN))
    if err != nil {
        return nil, err
    }

    return l, nil
}

// Ldap Connection without TLS
func Connect() (*ldap.Conn, error) {
    // You can also use IP instead of FQDN
    l, err := ldap.DialURL(fmt.Sprintf("ldap://%s:389", FQDN))
    if err != nil {
        return nil, err
    }

    return l, nil
}

// Anonymous Bind and Search
func AnonymousBindAndSearch(l *ldap.Conn) (*ldap.SearchResult, error) {
    l.UnauthenticatedBind("")

    anonReq := ldap.NewSearchRequest(
        "",
        ldap.ScopeBaseObject, // you can also use ldap.ScopeWholeSubtree
        ldap.NeverDerefAliases,
        0,
        0,
        false,
        Filter,
        []string{},
        nil,
    )
    result, err := l.Search(anonReq)
    if err != nil {
        return nil, fmt.Errorf("Anonymous Bind Search Error: %s", err)
    }

    if len(result.Entries) > 0 {
        result.Entries[0].Print()
        return result, nil
    } else {
        return nil, fmt.Errorf("Couldn't fetch anonymous bind search entries")
    }
}

// Normal Bind and Search
func BindAndSearch(l *ldap.Conn) (*ldap.SearchResult, error) {
    l.Bind(BindUsername, BindPassword)

    searchReq := ldap.NewSearchRequest(
        BaseDN,
        ldap.ScopeBaseObject, // you can also use ldap.ScopeWholeSubtree
        ldap.NeverDerefAliases,
        0,
        0,
        false,
        Filter,
        []string{},
        nil,
    )
    result, err := l.Search(searchReq)
    if err != nil {
        return nil, fmt.Errorf("Search Error: %s", err)
    }

    if len(result.Entries) > 0 {
        return result, nil
    } else {
        return nil, fmt.Errorf("Couldn't fetch search entries")
    }
}

You can also check out the gist I created.

Thank you for reading. I hope you found this article helpful.


This content originally appeared on DEV Community and was authored by Rıdvan Tülemen


Print Share Comment Cite Upload Translate Updates
APA

Rıdvan Tülemen | Sciencx (2021-06-30T19:31:52+00:00) LDAP Authentication in Golang with Bind and Search. Retrieved from https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/

MLA
" » LDAP Authentication in Golang with Bind and Search." Rıdvan Tülemen | Sciencx - Wednesday June 30, 2021, https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/
HARVARD
Rıdvan Tülemen | Sciencx Wednesday June 30, 2021 » LDAP Authentication in Golang with Bind and Search., viewed ,<https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/>
VANCOUVER
Rıdvan Tülemen | Sciencx - » LDAP Authentication in Golang with Bind and Search. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/
CHICAGO
" » LDAP Authentication in Golang with Bind and Search." Rıdvan Tülemen | Sciencx - Accessed . https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/
IEEE
" » LDAP Authentication in Golang with Bind and Search." Rıdvan Tülemen | Sciencx [Online]. Available: https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/. [Accessed: ]
rf:citation
» LDAP Authentication in Golang with Bind and Search | Rıdvan Tülemen | Sciencx | https://www.scien.cx/2021/06/30/ldap-authentication-in-golang-with-bind-and-search/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.