Gentoo Archives: gentoo-commits

From: "Manuel Rüger" <mrueg@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/gentoo:master commit in: sys-auth/docker_auth/files/, sys-auth/docker_auth/
Date: Tue, 26 Sep 2017 16:44:25
Message-Id: 1506444222.d4aea241bbc1e07d25e3ae16407df9b9ce765921.mrueg@gentoo
1 commit: d4aea241bbc1e07d25e3ae16407df9b9ce765921
2 Author: Manuel Rüger <mrueg <AT> gentoo <DOT> org>
3 AuthorDate: Tue Sep 26 16:43:42 2017 +0000
4 Commit: Manuel Rüger <mrueg <AT> gentoo <DOT> org>
5 CommitDate: Tue Sep 26 16:43:42 2017 +0000
6 URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=d4aea241
7
8 sys-auth/docker_auth: Add patch to set ldap cert
9
10 Package-Manager: Portage-2.3.10, Repoman-2.3.3
11
12 sys-auth/docker_auth/docker_auth-1.3-r1.ebuild | 88 +++++
13 .../files/docker_auth-ldap-cacert.patch | 67 ++++
14 .../files/docker_auth-ldap-group-support-1.patch | 394 +++++++++++++++++++++
15 3 files changed, 549 insertions(+)
16
17 diff --git a/sys-auth/docker_auth/docker_auth-1.3-r1.ebuild b/sys-auth/docker_auth/docker_auth-1.3-r1.ebuild
18 new file mode 100644
19 index 00000000000..ebeaf7fa15e
20 --- /dev/null
21 +++ b/sys-auth/docker_auth/docker_auth-1.3-r1.ebuild
22 @@ -0,0 +1,88 @@
23 +# Copyright 1999-2017 Gentoo Foundation
24 +# Distributed under the terms of the GNU General Public License v2
25 +
26 +EAPI=6
27 +EGO_PN="github.com/cesanta/docker_auth"
28 +
29 +EGO_VENDOR=(
30 + "github.com/dchest/uniuri 8902c56451e9b58ff940bbe5fec35d5f9c04584a"
31 + "github.com/deckarep/golang-set fc8930a5e645572ee00bf66358ed3414f3c13b90"
32 + "github.com/docker/distribution 0700fa570d7bcc1b3e46ee127c4489fd25f4daa3"
33 + "github.com/docker/libtrust aabc10ec26b754e797f9028f4589c5b7bd90dc20"
34 + "github.com/facebookgo/httpdown a3b1354551a26449fbe05f5d855937f6e7acbd71"
35 + "github.com/facebookgo/clock 600d898af40aa09a7a93ecb9265d87b0504b6f03"
36 + "github.com/facebookgo/stats 1b76add642e42c6ffba7211ad7b3939ce654526e"
37 + "github.com/go-ldap/ldap 13cedcf58a1ea124045dea529a66c849d3444c8e"
38 + "github.com/cesanta/glog 22eb27a0ae192b290b25537b8e876556fc25129c"
39 + "github.com/schwarmco/go-cartesian-product c2c0aca869a6cbf51e017ce148b949d9dee09bc3"
40 + "github.com/syndtr/goleveldb 3c5717caf1475fd25964109a0fc640bd150fce43"
41 + "github.com/golang/snappy 553a641470496b2327abcac10b36396bd98e45c9"
42 + "gopkg.in/asn1-ber.v1 4e86f4367175e39f69d9358a5f17b4dda270378d github.com/go-asn1-ber/asn1-ber"
43 + "gopkg.in/fsnotify.v1 629574ca2a5df945712d3079857300b5e4da0236 github.com/fsnotify/fsnotify"
44 + "gopkg.in/mgo.v2 3f83fa5005286a7fe593b055f0d7771a7dce4655 github.com/go-mgo/mgo"
45 + "gopkg.in/yaml.v2 a3f3340b5840cee44f372bddb5880fcbc419b46a github.com/go-yaml/yaml"
46 + "golang.org/x/crypto e1a4589e7d3ea14a3352255d04b6f1a418845e5e github.com/golang/crypto"
47 + "golang.org/x/sys 493114f68206f85e7e333beccfabc11e98cba8dd github.com/golang/sys"
48 + "golang.org/x/net 859d1a86bb617c0c20d154590c3c5d3fcb670b07 github.com/golang/net"
49 + "google.golang.org/api 39c3dd417c5a443607650f18e829ad308da08dd2 github.com/google/google-api-go-client"
50 + "google.golang.org/grpc 35170916ff58e89ae03f52e778228e18207e0e02 github.com/grpc/grpc-go"
51 + "github.com/golang/protobuf 11b8df160996e00fd4b55cbaafb3d84ec6d50fa8"
52 + "golang.org/x/oauth2 13449ad91cb26cb47661c1b080790392170385fd github.com/golang/oauth2"
53 + "cloud.google.com/go bbf380d59635bf267fc8a8df03d6d261c448ee3c github.com/GoogleCloudPlatform/gcloud-golang"
54 + "golang.org/x/text ab5ac5f9a8deb4855a60fab02bc61a4ec770bd49 github.com/golang/text"
55 + "github.com/googleapis/gax-go 8c160ca1523d8eea3932fbaa494c8964b7724aa8"
56 + "google.golang.org/genproto 595979c8a7bf586b2d293fb42246bf91a0b893d9 github.com/google/go-genproto"
57 + )
58 +
59 +inherit user golang-build golang-vcs-snapshot
60 +EGIT_COMMIT="2cd3699dab4e44a239db136a52734dab25897bee"
61 +SHORT_COMMIT=${EGIT_COMMIT:0:7}
62 +SRC_URI="https://${EGO_PN}/archive/${PV}.tar.gz -> ${P}.tar.gz
63 + ${EGO_VENDOR_URI}"
64 +KEYWORDS="~amd64"
65 +
66 +DESCRIPTION="Docker Registry 2 authentication server"
67 +HOMEPAGE="https://github.com/cesanta/docker_auth"
68 +
69 +LICENSE="Apache-2.0"
70 +SLOT="0"
71 +IUSE=""
72 +
73 +RESTRICT="test"
74 +
75 +pkg_setup() {
76 + enewgroup ${PN}
77 + enewuser ${PN} -1 -1 /dev/null ${PN}
78 +}
79 +
80 +src_prepare() {
81 + default
82 + pushd src/${EGO_PN}
83 + eapply "${FILESDIR}/${PN}-ldap-group-support-1.patch"
84 + eapply "${FILESDIR}/${PN}-ldap-cacert.patch"
85 + cp "${FILESDIR}/version.go" auth_server/version.go || die
86 + sed -i -e "s/{version}/${PV}/" -e "s/{build_id}/${SHORT_COMMIT}/" auth_server/version.go || die
87 + popd || die
88 +}
89 +
90 +src_compile() {
91 + pushd src/${EGO_PN}/auth_server || die
92 + GOPATH="${WORKDIR}/${P}" go build -o "bin/auth_server" || die
93 + popd || die
94 +}
95 +
96 +src_install() {
97 + pushd src/${EGO_PN} || die
98 + dodoc README.md docs/Backend_MongoDB.md
99 + insinto /usr/share/${PF}
100 + doins -r examples
101 + insinto /etc/docker_auth/
102 + newins examples/reference.yml config.yml.example
103 + dobin auth_server/bin/auth_server
104 + popd || die
105 + newinitd "${FILESDIR}"/${PN}.initd ${PN}
106 + newconfd "${FILESDIR}"/${PN}.confd ${PN}
107 + insinto /etc/logrotate.d
108 + newins "${FILESDIR}"/${PN}.logrotated ${PN}
109 + keepdir /var/log/docker_auth
110 +}
111
112 diff --git a/sys-auth/docker_auth/files/docker_auth-ldap-cacert.patch b/sys-auth/docker_auth/files/docker_auth-ldap-cacert.patch
113 new file mode 100644
114 index 00000000000..e43e9e6ca88
115 --- /dev/null
116 +++ b/sys-auth/docker_auth/files/docker_auth-ldap-cacert.patch
117 @@ -0,0 +1,67 @@
118 +From 5505de31a91aea88e0cf623ec8edfd928b5432a7 Mon Sep 17 00:00:00 2001
119 +From: =?UTF-8?q?Manuel=20R=C3=BCger?= <mrueg@g.o>
120 +Date: Mon, 18 Sep 2017 14:02:38 +0200
121 +Subject: [PATCH] Set custom CA certificate for ldap cert verification
122 +
123 +Code taken from: https://github.com/hashicorp/go-rootcerts/blob/master/rootcerts.go
124 +Original author: Paul Hinze <phinze@××××××.com>
125 +---
126 + auth_server/authn/ldap_auth.go | 17 ++++++++++++++++-
127 + examples/reference.yml | 2 ++
128 + 2 files changed, 18 insertions(+), 1 deletion(-)
129 +
130 +diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
131 +index 3bdf7c3..a3425ed 100644
132 +--- a/auth_server/authn/ldap_auth.go
133 ++++ b/auth_server/authn/ldap_auth.go
134 +@@ -19,6 +19,7 @@ package authn
135 + import (
136 + "bytes"
137 + "crypto/tls"
138 ++ "crypto/x509"
139 + "fmt"
140 + "io/ioutil"
141 + "strings"
142 +@@ -31,6 +32,7 @@ type LDAPAuthConfig struct {
143 + Addr string `yaml:"addr,omitempty"`
144 + TLS string `yaml:"tls,omitempty"`
145 + InsecureTLSSkipVerify bool `yaml:"insecure_tls_skip_verify,omitempty"`
146 ++ CACertificate string `yaml:"ca_certificate,omitempty"`
147 + Base string `yaml:"base,omitempty"`
148 + Filter string `yaml:"filter,omitempty"`
149 + BindDN string `yaml:"bind_dn,omitempty"`
150 +@@ -140,7 +142,20 @@ func (la *LDAPAuth) ldapConnection() (*ldap.Conn, error) {
151 + tlsConfig := &tls.Config{InsecureSkipVerify: true}
152 + if !la.config.InsecureTLSSkipVerify {
153 + addr := strings.Split(la.config.Addr, ":")
154 +- tlsConfig = &tls.Config{InsecureSkipVerify: false, ServerName: addr[0]}
155 ++ if la.config.CACertificate != "" {
156 ++ pool := x509.NewCertPool()
157 ++ pem, err := ioutil.ReadFile(la.config.CACertificate)
158 ++ if err != nil {
159 ++ return nil, fmt.Errorf("Error loading CA File: %s", err)
160 ++ }
161 ++ ok := pool.AppendCertsFromPEM(pem)
162 ++ if !ok {
163 ++ return nil, fmt.Errorf("Error loading CA File: Couldn't parse PEM in: %s", la.config.CACertificate)
164 ++ }
165 ++ tlsConfig = &tls.Config{InsecureSkipVerify: false, ServerName: addr[0], RootCAs: pool}
166 ++ } else {
167 ++ tlsConfig = &tls.Config{InsecureSkipVerify: false, ServerName: addr[0]}
168 ++ }
169 + }
170 +
171 + if la.config.TLS == "" || la.config.TLS == "none" || la.config.TLS == "starttls" {
172 +diff --git a/examples/reference.yml b/examples/reference.yml
173 +index 3090978..769cc91 100644
174 +--- a/examples/reference.yml
175 ++++ b/examples/reference.yml
176 +@@ -131,6 +131,8 @@ ldap_auth:
177 + tls: always
178 + # set to true to allow insecure tls
179 + insecure_tls_skip_verify: false
180 ++ # set this to specify the ca certificate path
181 ++ ca_cert:
182 + # In case bind DN and password is required for querying user information,
183 + # specify them here. Plain text password is read from the file.
184 + bind_dn:
185
186 diff --git a/sys-auth/docker_auth/files/docker_auth-ldap-group-support-1.patch b/sys-auth/docker_auth/files/docker_auth-ldap-group-support-1.patch
187 new file mode 100644
188 index 00000000000..f9e98f410c8
189 --- /dev/null
190 +++ b/sys-auth/docker_auth/files/docker_auth-ldap-group-support-1.patch
191 @@ -0,0 +1,394 @@
192 +From 4a33badac6b74617dfe3797a716a6907cf018b27 Mon Sep 17 00:00:00 2001
193 +From: Kevin <kcd83@××××××××××××××××××××.com>
194 +Date: Mon, 27 Feb 2017 19:09:52 +1300
195 +Subject: [PATCH 1/4] Initial proof of concept mapping memberOf CN to the label
196 + groups #63
197 +
198 +---
199 + auth_server/authn/ldap_auth.go | 73 ++++++++++++++++++++++++++++++++++--------
200 + 1 file changed, 60 insertions(+), 13 deletions(-)
201 +
202 +diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
203 +index f8fc08f..42f5ad0 100644
204 +--- a/auth_server/authn/ldap_auth.go
205 ++++ b/auth_server/authn/ldap_auth.go
206 +@@ -17,7 +17,6 @@
207 + package authn
208 +
209 + import (
210 +- "bytes"
211 + "crypto/tls"
212 + "fmt"
213 + "io/ioutil"
214 +@@ -71,10 +70,20 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
215 + account = la.escapeAccountInput(account)
216 +
217 + filter := la.getFilter(account)
218 +- accountEntryDN, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &[]string{})
219 ++
220 ++ // dnAndGroupAttr := []string{"DN"} // example of no groups mapping attribute
221 ++ groupAttribute := "memberOf"
222 ++ dnAndGroupAttr := []string{"DN", groupAttribute}
223 ++
224 ++ entryAttrMap, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &dnAndGroupAttr)
225 + if uSearchErr != nil {
226 + return false, nil, uSearchErr
227 + }
228 ++ if len(entryAttrMap) < 1 || entryAttrMap["DN"] == nil || len(entryAttrMap["DN"]) != 1 {
229 ++ return false, nil, NoMatch // User does not exist
230 ++ }
231 ++
232 ++ accountEntryDN := entryAttrMap["DN"][0]
233 + if accountEntryDN == "" {
234 + return false, nil, NoMatch // User does not exist
235 + }
236 +@@ -93,6 +102,20 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
237 + return false, nil, bindErr
238 + }
239 +
240 ++ // Extract group names from the attribute values
241 ++ if entryAttrMap[groupAttribute] != nil {
242 ++ rawGroups := entryAttrMap[groupAttribute]
243 ++ labels := make(map[string][]string)
244 ++ var groups []string
245 ++ for _, value := range rawGroups {
246 ++ cn := la.getCNFromDN(value)
247 ++ groups = append(groups, cn)
248 ++ }
249 ++ labels["groups"] = groups
250 ++
251 ++ return true, labels, nil
252 ++ }
253 ++
254 + return true, nil, nil
255 + }
256 +
257 +@@ -170,9 +193,9 @@ func (la *LDAPAuth) getFilter(account string) string {
258 +
259 + //ldap search and return required attributes' value from searched entries
260 + //default return entry's DN value if you leave attrs array empty
261 +-func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, error) {
262 ++func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (map[string][]string, error) {
263 + if l == nil {
264 +- return "", fmt.Errorf("No ldap connection!")
265 ++ return nil, fmt.Errorf("No ldap connection!")
266 + }
267 + glog.V(2).Infof("Searching...basedDN:%s, filter:%s", *baseDN, *filter)
268 + searchRequest := ldap.NewSearchRequest(
269 +@@ -183,30 +206,54 @@ func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, att
270 + nil)
271 + sr, err := l.Search(searchRequest)
272 + if err != nil {
273 +- return "", err
274 ++ return nil, err
275 + }
276 +
277 + if len(sr.Entries) == 0 {
278 +- return "", nil // User does not exist
279 ++ return nil, nil // User does not exist
280 + } else if len(sr.Entries) > 1 {
281 +- return "", fmt.Errorf("Too many entries returned.")
282 ++ return nil, fmt.Errorf("Too many entries returned.")
283 + }
284 +
285 +- var buffer bytes.Buffer
286 ++ result := make(map[string][]string)
287 + for _, entry := range sr.Entries {
288 ++
289 + if len(*attrs) == 0 {
290 + glog.V(2).Infof("Entry DN = %s", entry.DN)
291 +- buffer.WriteString(entry.DN)
292 ++ result["DN"] = []string{entry.DN}
293 + } else {
294 + for _, attr := range *attrs {
295 +- values := strings.Join(entry.GetAttributeValues(attr), " ")
296 +- glog.V(2).Infof("Entry %s = %s", attr, values)
297 +- buffer.WriteString(values)
298 ++ var values []string
299 ++ if attr == "DN" {
300 ++ // DN is excluded from attributes
301 ++ values = []string{entry.DN}
302 ++ } else {
303 ++ values = entry.GetAttributeValues(attr)
304 ++ }
305 ++ valuesString := strings.Join(values, "\n")
306 ++ glog.V(2).Infof("Entry %s = %s", attr, valuesString)
307 ++ result[attr] = values
308 ++ }
309 ++ }
310 ++ }
311 ++
312 ++ return result, nil
313 ++}
314 ++
315 ++func (la *LDAPAuth) getCNFromDN(dn string) string {
316 ++ parsedDN, err := ldap.ParseDN(dn)
317 ++ if err != nil || len(parsedDN.RDNs) > 0 {
318 ++ for _, rdn := range parsedDN.RDNs {
319 ++ for _, rdnAttr := range rdn.Attributes {
320 ++ if rdnAttr.Type == "CN" {
321 ++ return rdnAttr.Value
322 ++ }
323 + }
324 + }
325 + }
326 +
327 +- return buffer.String(), nil
328 ++ // else try using raw DN
329 ++ return dn
330 + }
331 +
332 + func (la *LDAPAuth) Stop() {
333 +
334 +From ddde2fa779e746d7e74cd972a4c6795c72f17ee6 Mon Sep 17 00:00:00 2001
335 +From: Kevin <kcd83@××××××××××××××××××××.com>
336 +Date: Tue, 28 Feb 2017 18:09:55 +1300
337 +Subject: [PATCH 2/4] Apply attribute mapping from configuration
338 +
339 +---
340 + auth_server/authn/ldap_auth.go | 125 ++++++++++++++++++++++++-----------------
341 + 1 file changed, 74 insertions(+), 51 deletions(-)
342 +
343 +diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
344 +index 42f5ad0..6f733a2 100644
345 +--- a/auth_server/authn/ldap_auth.go
346 ++++ b/auth_server/authn/ldap_auth.go
347 +@@ -26,16 +26,22 @@ import (
348 + "github.com/golang/glog"
349 + )
350 +
351 ++type LabelMap struct {
352 ++ Attribute string `yaml:"attribute,omitempty"`
353 ++ ParseCN bool `yaml:"parse_cn,omitempty"`
354 ++}
355 ++
356 + type LDAPAuthConfig struct {
357 +- Addr string `yaml:"addr,omitempty"`
358 +- TLS string `yaml:"tls,omitempty"`
359 +- InsecureTLSSkipVerify bool `yaml:"insecure_tls_skip_verify,omitempty"`
360 +- Base string `yaml:"base,omitempty"`
361 +- Filter string `yaml:"filter,omitempty"`
362 +- BindDN string `yaml:"bind_dn,omitempty"`
363 +- BindPasswordFile string `yaml:"bind_password_file,omitempty"`
364 +- GroupBaseDN string `yaml:"group_base_dn,omitempty"`
365 +- GroupFilter string `yaml:"group_filter,omitempty"`
366 ++ Addr string `yaml:"addr,omitempty"`
367 ++ TLS string `yaml:"tls,omitempty"`
368 ++ InsecureTLSSkipVerify bool `yaml:"insecure_tls_skip_verify,omitempty"`
369 ++ Base string `yaml:"base,omitempty"`
370 ++ Filter string `yaml:"filter,omitempty"`
371 ++ BindDN string `yaml:"bind_dn,omitempty"`
372 ++ BindPasswordFile string `yaml:"bind_password_file,omitempty"`
373 ++ LabelMaps map[string]LabelMap `yaml:"labels,omitempty"`
374 ++ GroupBaseDN string `yaml:"group_base_dn,omitempty"`
375 ++ GroupFilter string `yaml:"group_filter,omitempty"`
376 + }
377 +
378 + type LDAPAuth struct {
379 +@@ -71,22 +77,19 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
380 +
381 + filter := la.getFilter(account)
382 +
383 +- // dnAndGroupAttr := []string{"DN"} // example of no groups mapping attribute
384 +- groupAttribute := "memberOf"
385 +- dnAndGroupAttr := []string{"DN", groupAttribute}
386 ++ labelAttributes, labelsConfigErr := la.getLabelAttributes()
387 ++ if labelsConfigErr != nil {
388 ++ return false, nil, labelsConfigErr
389 ++ }
390 +
391 +- entryAttrMap, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &dnAndGroupAttr)
392 ++ accountEntryDN, entryAttrMap, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &labelAttributes)
393 + if uSearchErr != nil {
394 + return false, nil, uSearchErr
395 + }
396 +- if len(entryAttrMap) < 1 || entryAttrMap["DN"] == nil || len(entryAttrMap["DN"]) != 1 {
397 +- return false, nil, NoMatch // User does not exist
398 +- }
399 +-
400 +- accountEntryDN := entryAttrMap["DN"][0]
401 + if accountEntryDN == "" {
402 + return false, nil, NoMatch // User does not exist
403 + }
404 ++
405 + // Bind as the user to verify their password
406 + if len(accountEntryDN) > 0 {
407 + err := l.Bind(accountEntryDN, string(password))
408 +@@ -102,21 +105,13 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
409 + return false, nil, bindErr
410 + }
411 +
412 +- // Extract group names from the attribute values
413 +- if entryAttrMap[groupAttribute] != nil {
414 +- rawGroups := entryAttrMap[groupAttribute]
415 +- labels := make(map[string][]string)
416 +- var groups []string
417 +- for _, value := range rawGroups {
418 +- cn := la.getCNFromDN(value)
419 +- groups = append(groups, cn)
420 +- }
421 +- labels["groups"] = groups
422 +-
423 +- return true, labels, nil
424 ++ // Extract labels from the attribute values
425 ++ labels, labelsExtractErr := la.getLabelsFromMap(entryAttrMap)
426 ++ if labelsExtractErr != nil {
427 ++ return false, nil, labelsExtractErr
428 + }
429 +
430 +- return true, nil, nil
431 ++ return true, labels, nil
432 + }
433 +
434 + func (la *LDAPAuth) bindReadOnlyUser(l *ldap.Conn) error {
435 +@@ -193,9 +188,9 @@ func (la *LDAPAuth) getFilter(account string) string {
436 +
437 + //ldap search and return required attributes' value from searched entries
438 + //default return entry's DN value if you leave attrs array empty
439 +-func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (map[string][]string, error) {
440 ++func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, map[string][]string, error) {
441 + if l == nil {
442 +- return nil, fmt.Errorf("No ldap connection!")
443 ++ return "", nil, fmt.Errorf("No ldap connection!")
444 + }
445 + glog.V(2).Infof("Searching...basedDN:%s, filter:%s", *baseDN, *filter)
446 + searchRequest := ldap.NewSearchRequest(
447 +@@ -206,38 +201,66 @@ func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, att
448 + nil)
449 + sr, err := l.Search(searchRequest)
450 + if err != nil {
451 +- return nil, err
452 ++ return "", nil, err
453 + }
454 +
455 + if len(sr.Entries) == 0 {
456 +- return nil, nil // User does not exist
457 ++ return "", nil, nil // User does not exist
458 + } else if len(sr.Entries) > 1 {
459 +- return nil, fmt.Errorf("Too many entries returned.")
460 ++ return "", nil, fmt.Errorf("Too many entries returned.")
461 + }
462 +
463 +- result := make(map[string][]string)
464 ++ attributes := make(map[string][]string)
465 ++ var entryDn string
466 + for _, entry := range sr.Entries {
467 +-
468 ++ entryDn = entry.DN
469 + if len(*attrs) == 0 {
470 +- glog.V(2).Infof("Entry DN = %s", entry.DN)
471 +- result["DN"] = []string{entry.DN}
472 ++ glog.V(2).Infof("Entry DN = %s", entryDn)
473 + } else {
474 + for _, attr := range *attrs {
475 +- var values []string
476 +- if attr == "DN" {
477 +- // DN is excluded from attributes
478 +- values = []string{entry.DN}
479 +- } else {
480 +- values = entry.GetAttributeValues(attr)
481 +- }
482 +- valuesString := strings.Join(values, "\n")
483 +- glog.V(2).Infof("Entry %s = %s", attr, valuesString)
484 +- result[attr] = values
485 ++ values := entry.GetAttributeValues(attr)
486 ++ glog.V(2).Infof("Entry %s = %s", attr, strings.Join(values, "\n"))
487 ++ attributes[attr] = values
488 + }
489 + }
490 + }
491 +
492 +- return result, nil
493 ++ return entryDn, attributes, nil
494 ++}
495 ++
496 ++func (la *LDAPAuth) getLabelAttributes() ([]string, error) {
497 ++ labelAttributes := make([]string, len(la.config.LabelMaps))
498 ++ i := 0
499 ++ for key, mapping := range la.config.LabelMaps {
500 ++ if mapping.Attribute == "" {
501 ++ return nil, fmt.Errorf("Label %s is missing 'attribute' to map from", key)
502 ++ }
503 ++ labelAttributes[i] = mapping.Attribute
504 ++ i++
505 ++ }
506 ++ return labelAttributes, nil
507 ++}
508 ++
509 ++func (la *LDAPAuth) getLabelsFromMap(attrMap map[string][]string) (map[string][]string, error) {
510 ++ labels := make(map[string][]string)
511 ++ for key, mapping := range la.config.LabelMaps {
512 ++ if mapping.Attribute == "" {
513 ++ return nil, fmt.Errorf("Label %s is missing 'attribute' to map from", key)
514 ++ }
515 ++
516 ++ mappingValues := attrMap[mapping.Attribute]
517 ++ if mappingValues != nil {
518 ++ if mapping.ParseCN {
519 ++ // shorten attribute to its common name
520 ++ for i, value := range mappingValues {
521 ++ cn := la.getCNFromDN(value)
522 ++ mappingValues[i] = cn
523 ++ }
524 ++ }
525 ++ labels[key] = mappingValues
526 ++ }
527 ++ }
528 ++ return labels, nil
529 + }
530 +
531 + func (la *LDAPAuth) getCNFromDN(dn string) string {
532 +
533 +From cd37001980267a99a9faa19f1927891af63acb90 Mon Sep 17 00:00:00 2001
534 +From: Kevin <kcd83@××××××××××××××××××××.com>
535 +Date: Tue, 28 Feb 2017 18:27:16 +1300
536 +Subject: [PATCH 3/4] Remove unused configuration fields, never implemented?
537 +
538 +---
539 + auth_server/authn/ldap_auth.go | 2 --
540 + 1 file changed, 2 deletions(-)
541 +
542 +diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
543 +index 6f733a2..9c8bcb8 100644
544 +--- a/auth_server/authn/ldap_auth.go
545 ++++ b/auth_server/authn/ldap_auth.go
546 +@@ -40,8 +40,6 @@ type LDAPAuthConfig struct {
547 + BindDN string `yaml:"bind_dn,omitempty"`
548 + BindPasswordFile string `yaml:"bind_password_file,omitempty"`
549 + LabelMaps map[string]LabelMap `yaml:"labels,omitempty"`
550 +- GroupBaseDN string `yaml:"group_base_dn,omitempty"`
551 +- GroupFilter string `yaml:"group_filter,omitempty"`
552 + }
553 +
554 + type LDAPAuth struct {
555 +
556 +From 2fd43be4e5c2cfe177d9e1d36bcd1b29f4d6f262 Mon Sep 17 00:00:00 2001
557 +From: Kevin <kcd83@××××××××××××××××××××.com>
558 +Date: Fri, 1 Sep 2017 22:50:19 +1200
559 +Subject: [PATCH 4/4] Add LDAP label map examples to the reference config
560 +
561 +---
562 + examples/reference.yml | 10 ++++++++++
563 + 1 file changed, 10 insertions(+)
564 +
565 +diff --git a/examples/reference.yml b/examples/reference.yml
566 +index b8bb08c..40c5762 100644
567 +--- a/examples/reference.yml
568 ++++ b/examples/reference.yml
569 +@@ -134,6 +134,16 @@ ldap_auth:
570 + # User query settings. ${account} is expanded from auth request
571 + base: o=example.com
572 + filter: (&(uid=${account})(objectClass=person))
573 ++ # Labels can be mapped from LDAP attributes
574 ++ labels:
575 ++ # Add the user's title to a label called title
576 ++ title:
577 ++ attribute: title
578 ++ # Add the user's memberOf values to a label called groups
579 ++ groups:
580 ++ attribute: memberOf
581 ++ # Special handling to simplify the values to just the common name
582 ++ parse_cn: true
583 +
584 + mongo_auth:
585 + # Essentially all options are described here: https://godoc.org/gopkg.in/mgo.v2#DialInfo