aboutsummaryrefslogtreecommitdiff
path: root/ldapserver/route.go
diff options
context:
space:
mode:
Diffstat (limited to 'ldapserver/route.go')
-rw-r--r--ldapserver/route.go255
1 files changed, 255 insertions, 0 deletions
diff --git a/ldapserver/route.go b/ldapserver/route.go
new file mode 100644
index 0000000..d5bd00a
--- /dev/null
+++ b/ldapserver/route.go
@@ -0,0 +1,255 @@
+package ldapserver
+
+import (
+ "strings"
+
+ ldap "github.com/vjeantet/goldap/message"
+)
+
+// Constant to LDAP Request protocol Type names
+const (
+ SEARCH = "SearchRequest"
+ BIND = "BindRequest"
+ COMPARE = "CompareRequest"
+ ADD = "AddRequest"
+ MODIFY = "ModifyRequest"
+ DELETE = "DelRequest"
+ EXTENDED = "ExtendedRequest"
+ ABANDON = "AbandonRequest"
+)
+
+// 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 HandlerFunc func(UserState, ResponseWriter, *Message)
+
+// RouteMux manages all routes
+type RouteMux struct {
+ routes []*route
+ notFoundRoute *route
+}
+
+type route struct {
+ label string
+ operation string
+ handler HandlerFunc
+ exoName string
+ sBasedn string
+ uBasedn bool
+ sFilter string
+ uFilter bool
+ sScope int
+ uScope bool
+ sAuthChoice string
+ uAuthChoice bool
+}
+
+// Match return true when the *Message matches the route
+// conditions
+func (r *route) Match(m *Message) bool {
+ if m.ProtocolOpName() != r.operation {
+ return false
+ }
+
+ switch v := m.ProtocolOp().(type) {
+ case ldap.BindRequest:
+ if r.uAuthChoice == true {
+ if strings.ToLower(v.AuthenticationChoice()) != r.sAuthChoice {
+ return false
+ }
+ }
+ return true
+
+ case ldap.ExtendedRequest:
+ if string(v.RequestName()) != r.exoName {
+ return false
+ }
+ return true
+
+ case ldap.SearchRequest:
+ if r.uBasedn == true {
+ if strings.ToLower(string(v.BaseObject())) != r.sBasedn {
+ return false
+ }
+ }
+
+ if r.uFilter == true {
+ if strings.ToLower(v.FilterString()) != r.sFilter {
+ return false
+ }
+ }
+
+ if r.uScope == true {
+ if int(v.Scope()) != r.sScope {
+ return false
+ }
+ }
+ return true
+ }
+ return true
+}
+
+func (r *route) Label(label string) *route {
+ r.label = label
+ return r
+}
+
+func (r *route) BaseDn(dn string) *route {
+ r.sBasedn = strings.ToLower(dn)
+ r.uBasedn = true
+ return r
+}
+
+func (r *route) AuthenticationChoice(choice string) *route {
+ r.sAuthChoice = strings.ToLower(choice)
+ r.uAuthChoice = true
+ return r
+}
+
+func (r *route) Filter(pattern string) *route {
+ r.sFilter = strings.ToLower(pattern)
+ r.uFilter = true
+ return r
+}
+
+func (r *route) Scope(scope int) *route {
+ r.sScope = scope
+ r.uScope = true
+ return r
+}
+
+func (r *route) RequestName(name ldap.LDAPOID) *route {
+ r.exoName = string(name)
+ return r
+}
+
+// NewRouteMux returns a new *RouteMux
+// RouteMux implements ldapserver.Handler
+func NewRouteMux() *RouteMux {
+ return &RouteMux{}
+}
+
+// Handler interface used to serve a LDAP Request message
+type Handler interface {
+ ServeLDAP(s UserState, w ResponseWriter, r *Message)
+}
+
+// ServeLDAP dispatches the request to the handler whose
+// pattern most closely matches the request request Message.
+func (h *RouteMux) ServeLDAP(s UserState, w ResponseWriter, r *Message) {
+
+ //find a matching Route
+ for _, route := range h.routes {
+
+ //if the route don't match, skip it
+ if route.Match(r) == false {
+ continue
+ }
+
+ if route.label != "" {
+ Logger.Printf("")
+ Logger.Printf(" ROUTE MATCH ; %s", route.label)
+ Logger.Printf("")
+ // Logger.Printf(" ROUTE MATCH ; %s", runtime.FuncForPC(reflect.ValueOf(route.handler).Pointer()).Name())
+ }
+
+ route.handler(s, w, r)
+ return
+ }
+
+ // Catch a AbandonRequest not handled by user
+ switch v := r.ProtocolOp().(type) {
+ case ldap.AbandonRequest:
+ // retreive the request to abandon, and send a abort signal to it
+ if requestToAbandon, ok := r.Client.GetMessageByID(int(v)); ok {
+ requestToAbandon.Abandon()
+ }
+ }
+
+ if h.notFoundRoute != nil {
+ h.notFoundRoute.handler(s, w, r)
+ } else {
+ res := NewResponse(LDAPResultUnwillingToPerform)
+ res.SetDiagnosticMessage("Operation not implemented by server")
+ w.Write(res)
+ }
+}
+
+// Adds a new Route to the Handler
+func (h *RouteMux) addRoute(r *route) {
+ //and finally append to the list of Routes
+ //create the Route
+ h.routes = append(h.routes, r)
+}
+
+func (h *RouteMux) NotFound(handler HandlerFunc) *route {
+ route := &route{}
+ route.handler = handler
+ h.notFoundRoute = route
+ return route
+}
+
+func (h *RouteMux) Bind(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = BIND
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Search(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = SEARCH
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Add(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = ADD
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Delete(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = DELETE
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Modify(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = MODIFY
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Compare(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = COMPARE
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Extended(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = EXTENDED
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}
+
+func (h *RouteMux) Abandon(handler HandlerFunc) *route {
+ route := &route{}
+ route.operation = ABANDON
+ route.handler = handler
+ h.addRoute(route)
+ return route
+}