package main import ( "bytes" "encoding/base64" "fmt" "html/template" "log" "net/http" "regexp" "strings" "gopkg.in/ldap.v2" ) const ( host = "ldap.example.com" port = 389 topDn = "dc=example,dc=com" ) var ( fieldsRegExp = regexp.MustCompile(`[^\s,]+`) templates = template.New("").Funcs(template.FuncMap(map[string]interface{}{ "attribute": func(a *ldap.EntryAttribute) template.HTML { h := make([]string, len(a.Values)) switch a.Name { case "labeledURI": for i, v := range a.Values { pair := strings.SplitN(v, " ", 2) h[i] = fmt.Sprintf( "%s", template.HTMLEscapeString(pair[0]), template.HTMLEscapeString(pair[1])) } case "mail": for i, v := range a.Values { h[i] = fmt.Sprintf( "%s", template.HTMLEscapeString(v), template.HTMLEscapeString(v)) } case "jpegPhoto": for i, v := range a.ByteValues { h[i] = fmt.Sprintf( "", template.HTMLEscapeString( base64.StdEncoding.EncodeToString( v))) } case "roleOccupant": for i, v := range a.Values { h[i] = fmt.Sprintf( `%s`, template.HTMLEscapeString(v), template.HTMLEscapeString(v)) } default: for i, v := range a.Values { h[i] = template.HTMLEscapeString(v) } } return template.HTML(strings.Join(h, "
")) }, })) searchResultsTemplate = template.Must(templates.Parse(`
All People Roles Groups
{{- range .Result.Entries}}
{{- range .Attributes}} {{- end}}
{{.DN}}
{{.Name}} {{attribute .}}
{{- else}}
no results found
{{- end}}
`)) ) func search(filter string, fields string, baseDn string) (html []byte, err error) { l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) if err != nil { return } defer l.Close() search := ldap.NewSearchRequest( baseDn, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, filter, fieldsRegExp.FindAllString(fields, -1), nil) result, err := l.Search(search) if err != nil { return } data := struct { Result *ldap.SearchResult Filter string Fields string BaseDn string TopDn string }{ result, filter, fields, baseDn, topDn, } var b bytes.Buffer err = searchResultsTemplate.ExecuteTemplate(&b, "", data) if err != nil { return } html = b.Bytes() return } func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.Error(w, "Not Found", http.StatusNotFound) return } qs := r.URL.Query() filter := qs.Get("filter") if filter == "" { filter = "(objectClass=*)" } fields := qs.Get("fields") if fields == "" { fields = "*" } baseDn := qs.Get("base-dn") if baseDn == "" { baseDn = topDn } h, err := search(filter, fields, baseDn) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } w.Write(h) }) fmt.Printf("Listening at http://%s:12345\n", host) err := http.ListenAndServe(":12345", nil) if err != nil { log.Fatalf("Failed to ListenAndServe: %v", err) } }