ldapserver

package module
v1.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2022 License: GPL-2.0 Imports: 11 Imported by: 1

README

GoDoc Build Status

This package is a work in progress.

ldapserver is a helper library for building server software capable of speaking the LDAP protocol. This could be an alternate implementation of LDAP, a custom LDAP proxy or even a completely different backend capable of "masquerading" its API as a LDAP Server.

The package supports

  • All basic LDAP Operations (bind, search, add, compare, modify, delete, extended)
  • SSL
  • StartTLS
  • Unbind request is implemented, but is handled internally to close the connection.
  • Graceful stopping
  • Basic request routing inspired by net/http ServeMux
  • Logger customisation (log interface)

Default behaviors

Abandon request

If you don't set a route to handle AbandonRequest, the package will handle it for you. (signal sent to message.Done chan)

No Route Found

When no route matches the request, the server will first try to call a special NotFound route, if nothing is specified, it will return an UnwillingToResponse Error code (53)

Feel free to contribute, comment :)

Sample Code

// Listen to 10389 port for LDAP Request
// and route bind request to the handleBind func
package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	ldap "github.com/vjeantet/ldapserver"
)

func main() {
	//ldap logger
	ldap.Logger = log.New(os.Stdout, "[server] ", log.LstdFlags)

	//Create a new LDAP Server
	server := ldap.NewServer()

	routes := ldap.NewRouteMux()
	routes.Bind(handleBind)
	server.Handle(routes)

	// listen on 10389
	go server.ListenAndServe("127.0.0.1:10389")

	// When CTRL+C, SIGINT and SIGTERM signal occurs
	// Then stop server gracefully
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	<-ch
	close(ch)

	server.Stop()
}

// handleBind return Success if login == mysql
func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
	r := m.GetBindRequest()
	res := ldap.NewBindResponse(ldap.LDAPResultSuccess)

	if string(r.Name()) == "myLogin" {
		w.Write(res)
		return
	}

	log.Printf("Bind failed User=%s, Pass=%s", string(r.Name()), string(r.AuthenticationSimple()))
	res.SetResultCode(ldap.LDAPResultInvalidCredentials)
	res.SetDiagnosticMessage("invalid credentials")
	w.Write(res)
}

more examples

Look into the "examples" folder

Documentation

Index

Constants

View Source
const (
	ApplicationBindRequest           = 0
	ApplicationBindResponse          = 1
	ApplicationUnbindRequest         = 2
	ApplicationSearchRequest         = 3
	ApplicationSearchResultEntry     = 4
	ApplicationSearchResultDone      = 5
	ApplicationModifyRequest         = 6
	ApplicationModifyResponse        = 7
	ApplicationAddRequest            = 8
	ApplicationAddResponse           = 9
	ApplicationDelRequest            = 10
	ApplicationDelResponse           = 11
	ApplicationModifyDNRequest       = 12
	ApplicationModifyDNResponse      = 13
	ApplicationCompareRequest        = 14
	ApplicationCompareResponse       = 15
	ApplicationAbandonRequest        = 16
	ApplicationSearchResultReference = 19
	ApplicationExtendedRequest       = 23
	ApplicationExtendedResponse      = 24
)

LDAP Application Codes

View Source
const (
	LDAPResultSuccess                      = 0
	LDAPResultOperationsError              = 1
	LDAPResultProtocolError                = 2
	LDAPResultTimeLimitExceeded            = 3
	LDAPResultSizeLimitExceeded            = 4
	LDAPResultCompareFalse                 = 5
	LDAPResultCompareTrue                  = 6
	LDAPResultAuthMethodNotSupported       = 7
	LDAPResultStrongAuthRequired           = 8
	LDAPResultReferral                     = 10
	LDAPResultAdminLimitExceeded           = 11
	LDAPResultUnavailableCriticalExtension = 12
	LDAPResultConfidentialityRequired      = 13
	LDAPResultSaslBindInProgress           = 14
	LDAPResultNoSuchAttribute              = 16
	LDAPResultUndefinedAttributeType       = 17
	LDAPResultInappropriateMatching        = 18
	LDAPResultConstraintViolation          = 19
	LDAPResultAttributeOrValueExists       = 20
	LDAPResultInvalidAttributeSyntax       = 21
	LDAPResultNoSuchObject                 = 32
	LDAPResultAliasProblem                 = 33
	LDAPResultInvalidDNSyntax              = 34
	LDAPResultAliasDereferencingProblem    = 36
	LDAPResultInappropriateAuthentication  = 48
	LDAPResultInvalidCredentials           = 49
	LDAPResultInsufficientAccessRights     = 50
	LDAPResultBusy                         = 51
	LDAPResultUnavailable                  = 52
	LDAPResultUnwillingToPerform           = 53
	LDAPResultLoopDetect                   = 54
	LDAPResultNamingViolation              = 64
	LDAPResultObjectClassViolation         = 65
	LDAPResultNotAllowedOnNonLeaf          = 66
	LDAPResultNotAllowedOnRDN              = 67
	LDAPResultEntryAlreadyExists           = 68
	LDAPResultObjectClassModsProhibited    = 69
	LDAPResultAffectsMultipleDSAs          = 71
	LDAPResultOther                        = 80

	ErrorNetwork         = 200
	ErrorFilterCompile   = 201
	ErrorFilterDecompile = 202
	ErrorDebugging       = 203
)

LDAP Result Codes

View Source
const (
	ModifyRequestChangeOperationAdd     = 0
	ModifyRequestChangeOperationDelete  = 1
	ModifyRequestChangeOperationReplace = 2
)

Modify Request Operation code

View Source
const (
	NoticeOfDisconnection   ldap.LDAPOID = "1.3.6.1.4.1.1466.2003"
	NoticeOfCancel          ldap.LDAPOID = "1.3.6.1.1.8"
	NoticeOfStartTLS        ldap.LDAPOID = "1.3.6.1.4.1.1466.20037"
	NoticeOfWhoAmI          ldap.LDAPOID = "1.3.6.1.4.1.4203.1.11.3"
	NoticeOfGetConnectionID ldap.LDAPOID = "1.3.6.1.4.1.26027.1.6.2"
	NoticeOfPasswordModify  ldap.LDAPOID = "1.3.6.1.4.1.4203.1.11.1"
)

Extended operation responseName and requestName

View Source
const (
	SEARCH   = "SearchRequest"
	BIND     = "BindRequest"
	COMPARE  = "CompareRequest"
	ADD      = "AddRequest"
	MODIFY   = "ModifyRequest"
	DELETE   = "DelRequest"
	EXTENDED = "ExtendedRequest"
	ABANDON  = "AbandonRequest"
)

Constant to LDAP Request protocol Type names

View Source
const SearchRequestHomeSubtree = 2
View Source
const SearchRequestScopeBaseObject = 0
View Source
const SearchRequestSingleLevel = 1

Variables

View Source
var (
	// DiscardingLogger can be used to disable logging output
	DiscardingLogger = log.New(ioutil.Discard, "", 0)
)
View Source
var Logger logger

Functions

func NewAddResponse

func NewAddResponse(resultCode int) ldap.AddResponse

func NewBindResponse

func NewBindResponse(resultCode int) ldap.BindResponse

func NewCompareResponse

func NewCompareResponse(resultCode int) ldap.CompareResponse

func NewDeleteResponse

func NewDeleteResponse(resultCode int) ldap.DelResponse

func NewExtendedResponse

func NewExtendedResponse(resultCode int) ldap.ExtendedResponse

func NewModifyResponse

func NewModifyResponse(resultCode int) ldap.ModifyResponse

func NewResponse

func NewResponse(resultCode int) ldap.LDAPResult

func NewSearchResultDoneResponse

func NewSearchResultDoneResponse(resultCode int) ldap.SearchResultDone

func NewSearchResultEntry

func NewSearchResultEntry(objectname string) ldap.SearchResultEntry

Types

type Handler

type Handler interface {
	ServeLDAP(w ResponseWriter, r *Message)
}

Handler interface used to serve a LDAP Request message

type HandlerFunc

type HandlerFunc func(ResponseWriter, *Message)

HandlerFunc type is an adapter to allow the use of ordinary functions as LDAP handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.

type Message

type Message struct {
	*ldap.LDAPMessage
	Client *client
	Done   chan bool
}

func (*Message) Abandon

func (m *Message) Abandon()

Abandon close the Done channel, to notify handler's user function to stop any running process

func (*Message) GetAbandonRequest

func (m *Message) GetAbandonRequest() ldap.AbandonRequest

func (*Message) GetAddRequest

func (m *Message) GetAddRequest() ldap.AddRequest

func (*Message) GetBindRequest

func (m *Message) GetBindRequest() ldap.BindRequest

func (*Message) GetCompareRequest

func (m *Message) GetCompareRequest() ldap.CompareRequest

func (*Message) GetDeleteRequest

func (m *Message) GetDeleteRequest() ldap.DelRequest

func (*Message) GetExtendedRequest

func (m *Message) GetExtendedRequest() ldap.ExtendedRequest

func (*Message) GetModifyRequest

func (m *Message) GetModifyRequest() ldap.ModifyRequest

func (*Message) GetSearchRequest

func (m *Message) GetSearchRequest() ldap.SearchRequest

func (*Message) String

func (m *Message) String() string

type ResponseWriter

type ResponseWriter interface {
	// Write writes the LDAPResponse to the connection as part of an LDAP reply.
	Write(po ldap.ProtocolOp)
}

ResponseWriter interface is used by an LDAP handler to construct an LDAP response.

type RouteMux

type RouteMux struct {
	// contains filtered or unexported fields
}

RouteMux manages all routes

func NewRouteMux

func NewRouteMux() *RouteMux

NewRouteMux returns a new *RouteMux RouteMux implements ldapserver.Handler

func (*RouteMux) Abandon

func (h *RouteMux) Abandon(handler HandlerFunc) *route

func (*RouteMux) Add

func (h *RouteMux) Add(handler HandlerFunc) *route

func (*RouteMux) Bind

func (h *RouteMux) Bind(handler HandlerFunc) *route

func (*RouteMux) Compare

func (h *RouteMux) Compare(handler HandlerFunc) *route

func (*RouteMux) Delete

func (h *RouteMux) Delete(handler HandlerFunc) *route

func (*RouteMux) Extended

func (h *RouteMux) Extended(handler HandlerFunc) *route

func (*RouteMux) Modify

func (h *RouteMux) Modify(handler HandlerFunc) *route

func (*RouteMux) NotFound

func (h *RouteMux) NotFound(handler HandlerFunc) *route

func (*RouteMux) Search

func (h *RouteMux) Search(handler HandlerFunc) *route

func (*RouteMux) ServeLDAP

func (h *RouteMux) ServeLDAP(w ResponseWriter, r *Message)

ServeLDAP dispatches the request to the handler whose pattern most closely matches the request request Message.

type Server

type Server struct {
	Listener     net.Listener
	ReadTimeout  time.Duration // optional read timeout
	WriteTimeout time.Duration // optional write timeout

	// OnNewConnection, if non-nil, is called on new connections.
	// If it returns non-nil, the connection is closed.
	OnNewConnection func(c net.Conn) error

	// Handler handles ldap message received from client
	// it SHOULD "implement" RequestHandler interface
	Handler Handler
	// contains filtered or unexported fields
}

Server is an LDAP server.

func NewServer

func NewServer() *Server

NewServer return a LDAP Server

func (*Server) Handle

func (s *Server) Handle(h Handler)

Handle registers the handler for the server. If a handler already exists for pattern, Handle panics

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(addr string, options ...func(*Server)) error

ListenAndServe listens on the TCP network address s.Addr and then calls Serve to handle requests on incoming connections. If s.Addr is blank, ":389" is used.

func (*Server) Stop

func (s *Server) Stop()

Termination of the LDAP session is initiated by the server sending a Notice of Disconnection. In this case, each protocol peer gracefully terminates the LDAP session by ceasing exchanges at the LDAP message layer, tearing down any SASL layer, tearing down any TLS layer, and closing the transport connection. A protocol peer may determine that the continuation of any communication would be pernicious, and in this case, it may abruptly terminate the session by ceasing communication and closing the transport connection. In either case, when the LDAP session is terminated.

Directories

Path Synopsis
examples
simple
Listen to 10389 port for LDAP Request and route bind request to the handleBind func
Listen to 10389 port for LDAP Request and route bind request to the handleBind func
ssl

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL