15
Golang'de LDAP Authentication, Bind ve Search
Windows Active Directory veya Samba hakkında bilginiz varsa, LDAP hakkında halihazırda bilginiz olabilir. Ama yoksa, Wikipedia'daki açıklama şu şekildedir.
Lightweight Directory Access Protocol veya kısaca LDAP (Türkçe: Basit İndeks Erişim Protokolü) TCP/IP üzerinde çalışan indeks servislerini sorgulama ve değiştirme amacıyla kullanılan uygulama katmanı protokolü.
İlk olarak, kütüphaneyi indirmemiz gerekiyor:
go get github.com/go-ldap/ldap
Artık kütüphaneyi kullanmaya başlayabiliriz. İlk olarak, daha sonra kullanacağımız değişkenleri oluşturuyoruz(Eğer anonymous bind kullanacaksanız sadece Filter değişkeni yeterlidir):
const (
BindUsername = "[email protected]"
BindPassword = "password"
FQDN = "DC.example.com"
BaseDN = "cn=Configuration,dc=example,dc=com"
Filter = "(objectClass=*)"
)
LDAP'a bağlanmak için, ldap.DialURL()
fonksiyonunu kullanacağız. Aşağıdaki fonksiyon sadece bağlantı için kullanılacak bir fonksiyondur:
// 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
}
Eğer TLS Connection kullanmak istiyorsanız, aşağıdaki fonksiyonu kullanabilirsiniz:
// 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
}
Eğer anonymous bind kullanmak istiyorsanız, bu fonksiyonu kullanabilirsiniz:
// 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")
}
}
Onun yerine, normal bind kullanmak isterseniz:
// 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")
}
}
Son olarak, bu fonksiyonları kullanabileceğimiz bir main fonksiyona ihtiyacımız var.
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()
}
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()
}
Bu fonksiyonlar ile LDAP ile Authentication, bind ve search'ün anlaşılabildiğini düşünüyorum. Sonunda kod aşağıdaki gibi bir hale geliyor:
package main
import (
"fmt"
"log"
"github.com/go-ldap/ldap/v3"
)
const (
BindUsername = "[email protected]"
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")
}
}
Ayrıca, oluşturduğum gist'e de göz atabilirsiniz.
Okduğunuz için teşekkürler. Umarım yardımcı olabilmişimdir.
15