-
Notifications
You must be signed in to change notification settings - Fork 1
/
directory_ldap.go
122 lines (102 loc) · 3.11 KB
/
directory_ldap.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
package yodel
import (
"fmt"
"log"
"strings"
mapset "github.com/deckarep/golang-set"
"github.com/go-ldap/ldap"
"github.com/spf13/viper"
)
// LdapConfig represents all the configuration required to connect to an LDAP
// server and run queries.
type LdapConfig struct {
HostURL string
BindDN string
BindPassword string
GroupAttribute string
BaseDN string // Base DN on which to search
Filter string // Filter which uniquely identifies the user
}
// CNToGroupName will transform a full CN string
// ("cn=adminUser,ou=groups,dc=org,dc=example") to a group name ("adminUser").
func CNToGroupName(cn string) string {
// Pretty hacky!
i := strings.Index(cn, ",")
return cn[3:i]
}
// GenerateLdapConfig generates an LDAP config object from external config
// files or environment variables.
func GenerateLdapConfig() LdapConfig {
// Dynamically generate the bind dn
bind_dn := viper.GetString("ldap.bind_dn")
user := viper.GetString("ldap.bind_username")
if strings.Contains(bind_dn, "%s") {
bind_dn = fmt.Sprintf(bind_dn, user)
}
return LdapConfig{
HostURL: viper.GetString("ldap.host_url"),
BindDN: bind_dn,
BindPassword: viper.GetString("ldap.bind_password"),
GroupAttribute: viper.GetString("ldap.group_attribute"),
BaseDN: viper.GetString("ldap.base_dn"),
Filter: viper.GetString("ldap.filter"),
}
}
//////////////////////
// LdapDirectory represents a queryable LDAP directory service,
type LdapDirectory struct {
cache GroupSet
config LdapConfig
}
// NewLdapDirectory acts as a constructor for LdapDirectory
func NewLdapDirectory(config LdapConfig) *LdapDirectory {
l := new(LdapDirectory)
l.cache = mapset.NewSet()
l.config = config
return l
}
// Search performs a search against the configured LDAP server by
// substituting the `lookup` argument into the configured filter.
func (l LdapDirectory) Search(lookup string) (GroupSet, error) {
log.Print(l.config.HostURL)
ld, err := ldap.DialURL(l.config.HostURL)
if err != nil {
log.Fatal(err)
}
defer ld.Close()
log.Print("Dialed")
err = ld.Bind(l.config.BindDN, l.config.BindPassword)
if err != nil {
log.Fatal(err)
}
log.Print("Bound")
// Define search
filter := fmt.Sprintf(l.config.Filter, lookup)
searchRequest := ldap.NewSearchRequest(
l.config.BaseDN, // The base dn to search
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
filter, // The filter to apply
[]string{"cn", l.config.GroupAttribute}, // A list attributes to retrieve
nil,
)
log.Print("Defined search")
// Execute search
sr, err := ld.Search(searchRequest)
if err != nil {
log.Fatal(err)
}
log.Print("Searched")
// Assume that the first matching user is always the right one
entry := sr.Entries[0]
groups := entry.GetAttributeValues(l.config.GroupAttribute)
resultSet := mapset.NewSet()
for _, group := range groups {
resultSet.Add(CNToGroupName(group))
}
return resultSet, nil
}
// Sync gets this directory service ready to issue searches. In the case of
// LDAP, this method does nothing.
func (l LdapDirectory) Sync() error {
return nil
}