diff options
Diffstat (limited to 'ldapserver/route.go')
-rw-r--r-- | ldapserver/route.go | 255 |
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 +} |