-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
133 lines (121 loc) · 2.97 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"encoding/json"
"flag"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-ldap/ldap"
log "github.com/sirupsen/logrus"
)
const (
_defaultLdapAddr = "ldaps://ldap-server.example.edu"
_defaultBaseDN = "ou=People,dc=example,dc=edu"
)
var (
_ldapUri = flag.String("ldapURI", _defaultLdapAddr, "Full uri path to ldap server for lookups.")
_baseDN = flag.String("baseDN", _defaultBaseDN, "Base DN for search requests.")
_serverPort = flag.String("port", "9090", "Port number to listen on")
_apiKeyFilePath = flag.String("apiKeyFile", "./apikeys.txt", "Path to api key file.")
_loadedKeys []string
)
// ProxySearchRequest contains the filter to apply and the attribute names to return
type ProxySearchRequest struct {
Filter string `json:"filter"`
AttributeNames []string `json:"attributeNames"`
}
func main() {
flag.Parse()
if err := loadKeys(*_apiKeyFilePath); err != nil {
log.Fatal(err)
}
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Timeout(60 * time.Second))
r.Use(apiKeyChecker)
r.Post("/search", dirlookup)
http.ListenAndServe(":"+*_serverPort, r)
}
func loadKeys(path string) error {
fh, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
defer fh.Close()
slurp, err := ioutil.ReadAll(fh)
if err != nil {
log.Fatal(err)
}
lines := strings.Split(string(slurp), "\n")
for _, line := range lines {
if len(line) > 0 && line[0] != '#' {
_loadedKeys = append(_loadedKeys, line)
}
}
return nil
}
func dirlookup(w http.ResponseWriter, r *http.Request) {
dec := json.NewDecoder(r.Body)
defer r.Body.Close()
var psr ProxySearchRequest
if r.Method != "POST" {
http.Error(w, http.StatusText(400), 400)
return
}
if err := dec.Decode(&psr); err != nil {
http.Error(w, err.Error(), 400)
return
}
l, err := ldap.DialURL(*_ldapUri)
if err != nil {
log.Error(err)
http.Error(w, err.Error(), 500)
return
}
defer l.Close()
searchRequest := ldap.NewSearchRequest(
*_baseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
psr.Filter,
psr.AttributeNames,
nil,
)
sr, err := l.Search(searchRequest)
if err != nil {
log.Error(err)
http.Error(w, err.Error(), 500)
return
}
result := make([]map[string][]string, 0)
for _, entry := range sr.Entries {
profile := make(map[string][]string)
for _, v := range psr.AttributeNames {
profile[v] = entry.GetAttributeValues(v)
}
result = append(result, profile)
}
enc := json.NewEncoder(w)
enc.Encode(result)
}
func apiKeyChecker(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var auth bool
reqKey := r.Header.Get("x-api-key")
for _, v := range _loadedKeys {
if reqKey == v {
auth = true
}
}
if reqKey == "" || !auth {
http.Error(w, http.StatusText(401), 401)
return
}
next.ServeHTTP(w, r)
})
}