From f4e67fa4cd924fbe6f271611514caf5589e6a6e5 Mon Sep 17 00:00:00 2001 From: ned Date: Wed, 12 Nov 2014 14:52:16 -0700 Subject: LDAP server support --- examples/cert_DONOTUSE.pem | 18 ++++++++ examples/key_DONOTUSE.pem | 27 ++++++++++++ examples/modify.go | 2 +- examples/proxy.go | 106 +++++++++++++++++++++++++++++++++++++++++++++ examples/search.go | 2 +- examples/searchSSL.go | 2 +- examples/searchTLS.go | 2 +- examples/server.go | 64 +++++++++++++++++++++++++++ 8 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 examples/cert_DONOTUSE.pem create mode 100644 examples/key_DONOTUSE.pem create mode 100644 examples/proxy.go create mode 100644 examples/server.go (limited to 'examples') diff --git a/examples/cert_DONOTUSE.pem b/examples/cert_DONOTUSE.pem new file mode 100644 index 0000000..ee14324 --- /dev/null +++ b/examples/cert_DONOTUSE.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9jCCAeCgAwIBAgIRAOG6xrSjAWQvJl9xFTIte/owCwYJKoZIhvcNAQELMBIx +EDAOBgNVBAoTB0FjbWUgQ28wHhcNMTQwODIwMTY1MjQ4WhcNMTUwODIwMTY1MjQ4 +WjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA30gcjawL7RXQ5B5IfAcCPsJkG3GBbfhkbBRI22VxktBoNvqh2TWyECG3 +WsB/N1WMmATnLxamBZ5mfouNbd120gbO1M06Ti57NP1YTmMp8AU18Dm4OjZ6IeQf +ip1xYSSSb6UyucFN6zIt+5PY2o4DoGb6fSNKb1ybgu91LmC1O/TDlyYUWn2TtF73 +FOUwSt+A6t3/Jhjhlp4n5Oobw1rrAgf7DPhWFg0Thj1yknPzWALY2LPREOMWob0D +EgR5C3WS2eYPyHkeMZWoSY6BiWTIU+hFqQUkdOvrWhflFoiZIsOl6iXmQpo2EQlg +j3Oy2zyZk1ndAfHlFoAgPIIbnBc+2QIDAQABo0swSTAOBgNVHQ8BAf8EBAMCAKAw +EwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNVHREEDTALggls +b2NhbGhvc3QwCwYJKoZIhvcNAQELA4IBAQBB9xNt3rDrBA9tCLCjdlnIQuUu9Uf0 +tHsSH6keBkhEoAylzHjmkNlerhTaLkRgB0D8qjE5+1APz42TuRpHRunYHSTNN0aF +N6zKlpXS0g+J/ViCh/Zw7xQI4mpSFqYzTgn4T733FqwLrmtKsj0IOOkDYSZc7qfh +qwXp/SB1J0Kp8G8S3G73dCZZYuW8y/eYMEoSkjNwNLAXzEAmFkGd8f1xhWTvnOxz +ZBbOOjggdRLxr7cMZ8GaVWFgEG93y3AYMhFxZYRwWTcWJvSTNP3xC/CWqxXkiKdO +2BROqmTw8zdqjXCIbgX4B5G5njMq9fk0gc4SiTAQkCOF6Xo0wQUvBAbN +-----END CERTIFICATE----- diff --git a/examples/key_DONOTUSE.pem b/examples/key_DONOTUSE.pem new file mode 100644 index 0000000..7feaa11 --- /dev/null +++ b/examples/key_DONOTUSE.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEoQIBAAKCAQEA30gcjawL7RXQ5B5IfAcCPsJkG3GBbfhkbBRI22VxktBoNvqh +2TWyECG3WsB/N1WMmATnLxamBZ5mfouNbd120gbO1M06Ti57NP1YTmMp8AU18Dm4 +OjZ6IeQfip1xYSSSb6UyucFN6zIt+5PY2o4DoGb6fSNKb1ybgu91LmC1O/TDlyYU +Wn2TtF73FOUwSt+A6t3/Jhjhlp4n5Oobw1rrAgf7DPhWFg0Thj1yknPzWALY2LPR +EOMWob0DEgR5C3WS2eYPyHkeMZWoSY6BiWTIU+hFqQUkdOvrWhflFoiZIsOl6iXm +Qpo2EQlgj3Oy2zyZk1ndAfHlFoAgPIIbnBc+2QIDAQABAoIBAGXECi+QEMd4QAMY +wlS1JRLRqqrPavxiT/Lqs+I7NC6EClu0k/vZ+1Ra6aTVQ6ZGuZO3+F5/5h99eJ2I +oWdHnxZOwApBl6d2i/U02wCvNbgNx+27gPoXRkcYIEAfTkPGVW/JTXtYXVkrP8YA +NsA2JfT/un86jHyBKufcl/4RWcj/BddduEWZRAV7UH4iUVzr6kTHJHyIkrJrME4w +0Njrd/+tvjX/AsBfj+4IqZo6yMSVQuGhnJYEWt+eU3+5OlLsWe8oy9PJN2hVPxvG +bWaMx0/I88gSf9DQRnpIL2Kr715c4NUqy+82DP+Tg6h/lQ1oba68redtZoctDrmq +IXox6PkCgYEA+fElqxWqdDTOw+yhD4CeZ6yxipI/iUQu2t7atRmTgi2WAgaT5aAP +1lWhTmWPW7IzjYzFe/CK7OAe0P7JgmvBI2SMlSg/NWOx+pnTmOVO3buz46+B3VI9 +IFhMqAkVfnXukT0YgLsdvRTZb7irYeelVImZ0VVvn0+HzqZ1JUj8kwMCgYEA5LGK +jZ0NmBQT/yxsp1GWlmIJnTizlxEGoc7ftL4SNGcshMKbSK6aYnUvjnnRdFwjQUu4 +mAN0LlDn7SalEL7PUnotUMNA278o4Zj88VcWQqjukkThDpOFVcreXuGkqIfxYyn6 +jJxLouF6L0zspEhFiEWjNYOVDzZw7Fh0tOCxkfMCf1L8voUPrIjo/74N02xSSEYk +EM7xwCbTfLsvQ27eDxwqBqSlinWzr4564BQnpHHNuVBGbUu5kmcUAydhcYbcQESA +Hi1oL5SKhY2vhZI+kPEOYaw3mebiZ2lV6B3i5kAW6B9RKdGUT0t4oLl3l2/qefqX +tXrL40QCJBV5L2wxz6sCgYEAoDRXUTkSCtUV5Q3j15pqGVL4VTEhbdQ5hyR6xgzY +h+k24JHLYjEeaZaaB/8CYbch413+JE9XFhMLRbBqtb5VUfvQvuDpEIdrRg58MzzE +lVHuPn0OA74IC7+f42vCg2UoDkWcBOCAg8vcYkJLDBKs0veli5lv1EZY+NhGeWdm +PU0CgYAhEHZnVC8DuKAUxuIXEpDil3F7iGYs1rAnGd3GkKofiait+9YlsCxFx/4F +95VQjHm6Fdc+vwGUa2Z986wKmocWzVP3TbznMdbvr0/8LCOhQKDrtCkFWHtGsP/d +PnCkwIdaTEen0E52PkMK8GNq6wjitINzRp5hpV23WFtGQxmmlA== +-----END RSA PRIVATE KEY----- diff --git a/examples/modify.go b/examples/modify.go index 326598c..87d1119 100644 --- a/examples/modify.go +++ b/examples/modify.go @@ -11,7 +11,7 @@ import ( "fmt" "log" - "github.com/vanackere/ldap" + "github.com/nmcclain/ldap" ) var ( diff --git a/examples/proxy.go b/examples/proxy.go new file mode 100644 index 0000000..d6b01d0 --- /dev/null +++ b/examples/proxy.go @@ -0,0 +1,106 @@ +package main + +import ( + "crypto/sha256" + "fmt" + "github.com/nmcclain/ldap" + "log" + "net" + "sync" +) + +type ldapHandler struct { + sessions map[string]session + lock sync.Mutex + ldapServer string + ldapPort int +} + +///////////// Run a simple LDAP proxy +func main() { + s := ldap.NewServer() + + handler := ldapHandler{ + sessions: make(map[string]session), + ldapServer: "localhost", + ldapPort: 3389, + } + s.BindFunc("", handler) + s.SearchFunc("", handler) + s.CloseFunc("", handler) + + // start the server + if err := s.ListenAndServe("localhost:3388"); err != nil { + log.Fatal("LDAP Server Failed: %s", err.Error()) + } +} + +///////////// +type session struct { + id string + c net.Conn + ldap *ldap.Conn +} + +func (h ldapHandler) getSession(conn net.Conn) (session, error) { + id := connID(conn) + h.lock.Lock() + s, ok := h.sessions[id] // use server connection if it exists + h.lock.Unlock() + if !ok { // open a new server connection if not + l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", h.ldapServer, h.ldapPort)) + if err != nil { + return session{}, err + } + s = session{id: id, c: conn, ldap: l} + h.lock.Lock() + h.sessions[s.id] = s + h.lock.Unlock() + } + return s, nil +} + +///////////// +func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, error) { + s, err := h.getSession(conn) + if err != nil { + return ldap.LDAPResultOperationsError, err + } + if err := s.ldap.Bind(bindDN, bindSimplePw); err != nil { + return ldap.LDAPResultOperationsError, err + } + return ldap.LDAPResultSuccess, nil +} + +///////////// +func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { + s, err := h.getSession(conn) + if err != nil { + return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, nil + } + search := ldap.NewSearchRequest( + searchReq.BaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, + searchReq.Filter, + searchReq.Attributes, + nil) + sr, err := s.ldap.Search(search) + if err != nil { + return ldap.ServerSearchResult{}, err + } + //log.Printf("P: Search OK: %s -> num of entries = %d\n", search.Filter, len(sr.Entries)) + return ldap.ServerSearchResult{sr.Entries, []string{}, []ldap.Control{}, ldap.LDAPResultSuccess}, nil +} +func (h ldapHandler) Close(conn net.Conn) error { + conn.Close() // close connection to the server when then client is closed + h.lock.Lock() + defer h.lock.Unlock() + delete(h.sessions, connID(conn)) + return nil +} +func connID(conn net.Conn) string { + h := sha256.New() + h.Write([]byte(conn.LocalAddr().String() + conn.RemoteAddr().String())) + sha := fmt.Sprintf("% x", h.Sum(nil)) + return string(sha) +} diff --git a/examples/search.go b/examples/search.go index 93e941c..08b364a 100644 --- a/examples/search.go +++ b/examples/search.go @@ -10,7 +10,7 @@ import ( "fmt" "log" - "github.com/vanackere/ldap" + "github.com/nmcclain/ldap" ) var ( diff --git a/examples/searchSSL.go b/examples/searchSSL.go index db2f7b8..75c8395 100644 --- a/examples/searchSSL.go +++ b/examples/searchSSL.go @@ -10,7 +10,7 @@ import ( "fmt" "log" - "github.com/vanackere/ldap" + "github.com/nmcclain/ldap" ) var ( diff --git a/examples/searchTLS.go b/examples/searchTLS.go index b4dce8a..56b3d27 100644 --- a/examples/searchTLS.go +++ b/examples/searchTLS.go @@ -10,7 +10,7 @@ import ( "fmt" "log" - "github.com/vanackere/ldap" + "github.com/nmcclain/ldap" ) var ( diff --git a/examples/server.go b/examples/server.go new file mode 100644 index 0000000..dca74ed --- /dev/null +++ b/examples/server.go @@ -0,0 +1,64 @@ +package main + +import ( + "github.com/nmcclain/ldap" + "log" + "net" +) + +///////////// +// Sample searches you can try against this simple LDAP server: +// +// ldapsearch -H ldap://localhost:3389 -x -b 'dn=test,dn=com' +// ldapsearch -H ldap://localhost:3389 -x -b 'dn=test,dn=com' 'cn=ned' +// ldapsearch -H ldap://localhost:3389 -x -b 'dn=test,dn=com' 'uidnumber=5000' +///////////// + +///////////// Run a simple LDAP server +func main() { + s := ldap.NewServer() + + // register Bind and Search function handlers + handler := ldapHandler{} + s.BindFunc("", handler) + s.SearchFunc("", handler) + + // start the server + if err := s.ListenAndServe("localhost:3389"); err != nil { + log.Fatal("LDAP Server Failed: %s", err.Error()) + } +} + +type ldapHandler struct { +} + +///////////// Allow anonymous binds only +func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, error) { + if bindDN == "" && bindSimplePw == "" { + return ldap.LDAPResultSuccess, nil + } + return ldap.LDAPResultInvalidCredentials, nil +} + +///////////// Return some hardcoded search results - we'll respond to any baseDN for testing +func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { + entries := []*ldap.Entry{ + &ldap.Entry{"cn=ned," + searchReq.BaseDN, []*ldap.EntryAttribute{ + &ldap.EntryAttribute{"cn", []string{"ned"}}, + &ldap.EntryAttribute{"uidNumber", []string{"5000"}}, + &ldap.EntryAttribute{"accountStatus", []string{"active"}}, + &ldap.EntryAttribute{"uid", []string{"ned"}}, + &ldap.EntryAttribute{"description", []string{"ned"}}, + &ldap.EntryAttribute{"objectClass", []string{"posixAccount"}}, + }}, + &ldap.Entry{"cn=trent," + searchReq.BaseDN, []*ldap.EntryAttribute{ + &ldap.EntryAttribute{"cn", []string{"trent"}}, + &ldap.EntryAttribute{"uidNumber", []string{"5005"}}, + &ldap.EntryAttribute{"accountStatus", []string{"active"}}, + &ldap.EntryAttribute{"uid", []string{"trent"}}, + &ldap.EntryAttribute{"description", []string{"trent"}}, + &ldap.EntryAttribute{"objectClass", []string{"posixAccount"}}, + }}, + } + return ldap.ServerSearchResult{entries, []string{}, []ldap.Control{}, ldap.LDAPResultSuccess}, nil +} -- cgit v1.2.3