Files
ldaps/examples/proxy.go
b9bf4d1baf Start tls by @shipperizer (#1)
* switch nmcclain/asn1-ber to go-asn1-ber/and1-ber.
This newer package has ben updated with tests, and looks to actually be supported.
It is also is a forked version of nmcclain/asn1-ber, so supports the same API.

* no need to print errors if client disconnects early and unexpectedly

* added in Close method on server to avoid a race condition

* test ssl certs are untrusted, ldapsearch needs to be told to allow untrusted certs

* Extra time.Wait causes the test to fail

* removed singaling with a custom quit chanel

* feat: support StartTLS in server

* lint: fmt and imports

* feat: rename library to be used by glauth

* chore: renamed packages

---------

Co-authored-by: Daniel Barney <daniel@thoughtplot.io>
Co-authored-by: Mark Rushakoff <mark@influxdata.com>
Co-authored-by: shipperizer <alexcabb@gmail.com>
2023-12-10 14:58:23 -08:00

111 lines
2.7 KiB
Go

//go:build ignore
// +build ignore
package main
import (
"crypto/sha256"
"fmt"
"log"
"net"
"sync"
"github.com/glauth/ldap"
)
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) (ldap.LDAPResultCode, 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(boundDN string, 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)
}