summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sys-auth/docker_auth/files/docker_auth-ldap-group-support.patch')
-rw-r--r--sys-auth/docker_auth/files/docker_auth-ldap-group-support.patch363
1 files changed, 363 insertions, 0 deletions
diff --git a/sys-auth/docker_auth/files/docker_auth-ldap-group-support.patch b/sys-auth/docker_auth/files/docker_auth-ldap-group-support.patch
new file mode 100644
index 000000000000..69858872f496
--- /dev/null
+++ b/sys-auth/docker_auth/files/docker_auth-ldap-group-support.patch
@@ -0,0 +1,363 @@
+From 4a33badac6b74617dfe3797a716a6907cf018b27 Mon Sep 17 00:00:00 2001
+From: Kevin <kcd83@users.noreply.github.com>
+Date: Mon, 27 Feb 2017 19:09:52 +1300
+Subject: [PATCH 1/3] Initial proof of concept mapping memberOf CN to the label
+ groups #63
+
+---
+ auth_server/authn/ldap_auth.go | 73 ++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 60 insertions(+), 13 deletions(-)
+
+diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
+index f8fc08f..42f5ad0 100644
+--- a/auth_server/authn/ldap_auth.go
++++ b/auth_server/authn/ldap_auth.go
+@@ -17,7 +17,6 @@
+ package authn
+
+ import (
+- "bytes"
+ "crypto/tls"
+ "fmt"
+ "io/ioutil"
+@@ -71,10 +70,20 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
+ account = la.escapeAccountInput(account)
+
+ filter := la.getFilter(account)
+- accountEntryDN, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &[]string{})
++
++ // dnAndGroupAttr := []string{"DN"} // example of no groups mapping attribute
++ groupAttribute := "memberOf"
++ dnAndGroupAttr := []string{"DN", groupAttribute}
++
++ entryAttrMap, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &dnAndGroupAttr)
+ if uSearchErr != nil {
+ return false, nil, uSearchErr
+ }
++ if len(entryAttrMap) < 1 || entryAttrMap["DN"] == nil || len(entryAttrMap["DN"]) != 1 {
++ return false, nil, NoMatch // User does not exist
++ }
++
++ accountEntryDN := entryAttrMap["DN"][0]
+ if accountEntryDN == "" {
+ return false, nil, NoMatch // User does not exist
+ }
+@@ -93,6 +102,20 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
+ return false, nil, bindErr
+ }
+
++ // Extract group names from the attribute values
++ if entryAttrMap[groupAttribute] != nil {
++ rawGroups := entryAttrMap[groupAttribute]
++ labels := make(map[string][]string)
++ var groups []string
++ for _, value := range rawGroups {
++ cn := la.getCNFromDN(value)
++ groups = append(groups, cn)
++ }
++ labels["groups"] = groups
++
++ return true, labels, nil
++ }
++
+ return true, nil, nil
+ }
+
+@@ -170,9 +193,9 @@ func (la *LDAPAuth) getFilter(account string) string {
+
+ //ldap search and return required attributes' value from searched entries
+ //default return entry's DN value if you leave attrs array empty
+-func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, error) {
++func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (map[string][]string, error) {
+ if l == nil {
+- return "", fmt.Errorf("No ldap connection!")
++ return nil, fmt.Errorf("No ldap connection!")
+ }
+ glog.V(2).Infof("Searching...basedDN:%s, filter:%s", *baseDN, *filter)
+ searchRequest := ldap.NewSearchRequest(
+@@ -183,30 +206,54 @@ func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, att
+ nil)
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+- return "", err
++ return nil, err
+ }
+
+ if len(sr.Entries) == 0 {
+- return "", nil // User does not exist
++ return nil, nil // User does not exist
+ } else if len(sr.Entries) > 1 {
+- return "", fmt.Errorf("Too many entries returned.")
++ return nil, fmt.Errorf("Too many entries returned.")
+ }
+
+- var buffer bytes.Buffer
++ result := make(map[string][]string)
+ for _, entry := range sr.Entries {
++
+ if len(*attrs) == 0 {
+ glog.V(2).Infof("Entry DN = %s", entry.DN)
+- buffer.WriteString(entry.DN)
++ result["DN"] = []string{entry.DN}
+ } else {
+ for _, attr := range *attrs {
+- values := strings.Join(entry.GetAttributeValues(attr), " ")
+- glog.V(2).Infof("Entry %s = %s", attr, values)
+- buffer.WriteString(values)
++ var values []string
++ if attr == "DN" {
++ // DN is excluded from attributes
++ values = []string{entry.DN}
++ } else {
++ values = entry.GetAttributeValues(attr)
++ }
++ valuesString := strings.Join(values, "\n")
++ glog.V(2).Infof("Entry %s = %s", attr, valuesString)
++ result[attr] = values
++ }
++ }
++ }
++
++ return result, nil
++}
++
++func (la *LDAPAuth) getCNFromDN(dn string) string {
++ parsedDN, err := ldap.ParseDN(dn)
++ if err != nil || len(parsedDN.RDNs) > 0 {
++ for _, rdn := range parsedDN.RDNs {
++ for _, rdnAttr := range rdn.Attributes {
++ if rdnAttr.Type == "CN" {
++ return rdnAttr.Value
++ }
+ }
+ }
+ }
+
+- return buffer.String(), nil
++ // else try using raw DN
++ return dn
+ }
+
+ func (la *LDAPAuth) Stop() {
+
+From ddde2fa779e746d7e74cd972a4c6795c72f17ee6 Mon Sep 17 00:00:00 2001
+From: Kevin <kcd83@users.noreply.github.com>
+Date: Tue, 28 Feb 2017 18:09:55 +1300
+Subject: [PATCH 2/3] Apply attribute mapping from configuration
+
+---
+ auth_server/authn/ldap_auth.go | 125 ++++++++++++++++++++++++-----------------
+ 1 file changed, 74 insertions(+), 51 deletions(-)
+
+diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
+index 42f5ad0..6f733a2 100644
+--- a/auth_server/authn/ldap_auth.go
++++ b/auth_server/authn/ldap_auth.go
+@@ -26,16 +26,22 @@ import (
+ "github.com/golang/glog"
+ )
+
++type LabelMap struct {
++ Attribute string `yaml:"attribute,omitempty"`
++ ParseCN bool `yaml:"parse_cn,omitempty"`
++}
++
+ type LDAPAuthConfig struct {
+- Addr string `yaml:"addr,omitempty"`
+- TLS string `yaml:"tls,omitempty"`
+- InsecureTLSSkipVerify bool `yaml:"insecure_tls_skip_verify,omitempty"`
+- Base string `yaml:"base,omitempty"`
+- Filter string `yaml:"filter,omitempty"`
+- BindDN string `yaml:"bind_dn,omitempty"`
+- BindPasswordFile string `yaml:"bind_password_file,omitempty"`
+- GroupBaseDN string `yaml:"group_base_dn,omitempty"`
+- GroupFilter string `yaml:"group_filter,omitempty"`
++ Addr string `yaml:"addr,omitempty"`
++ TLS string `yaml:"tls,omitempty"`
++ InsecureTLSSkipVerify bool `yaml:"insecure_tls_skip_verify,omitempty"`
++ Base string `yaml:"base,omitempty"`
++ Filter string `yaml:"filter,omitempty"`
++ BindDN string `yaml:"bind_dn,omitempty"`
++ BindPasswordFile string `yaml:"bind_password_file,omitempty"`
++ LabelMaps map[string]LabelMap `yaml:"labels,omitempty"`
++ GroupBaseDN string `yaml:"group_base_dn,omitempty"`
++ GroupFilter string `yaml:"group_filter,omitempty"`
+ }
+
+ type LDAPAuth struct {
+@@ -71,22 +77,19 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
+
+ filter := la.getFilter(account)
+
+- // dnAndGroupAttr := []string{"DN"} // example of no groups mapping attribute
+- groupAttribute := "memberOf"
+- dnAndGroupAttr := []string{"DN", groupAttribute}
++ labelAttributes, labelsConfigErr := la.getLabelAttributes()
++ if labelsConfigErr != nil {
++ return false, nil, labelsConfigErr
++ }
+
+- entryAttrMap, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &dnAndGroupAttr)
++ accountEntryDN, entryAttrMap, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &labelAttributes)
+ if uSearchErr != nil {
+ return false, nil, uSearchErr
+ }
+- if len(entryAttrMap) < 1 || entryAttrMap["DN"] == nil || len(entryAttrMap["DN"]) != 1 {
+- return false, nil, NoMatch // User does not exist
+- }
+-
+- accountEntryDN := entryAttrMap["DN"][0]
+ if accountEntryDN == "" {
+ return false, nil, NoMatch // User does not exist
+ }
++
+ // Bind as the user to verify their password
+ if len(accountEntryDN) > 0 {
+ err := l.Bind(accountEntryDN, string(password))
+@@ -102,21 +105,13 @@ func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool,
+ return false, nil, bindErr
+ }
+
+- // Extract group names from the attribute values
+- if entryAttrMap[groupAttribute] != nil {
+- rawGroups := entryAttrMap[groupAttribute]
+- labels := make(map[string][]string)
+- var groups []string
+- for _, value := range rawGroups {
+- cn := la.getCNFromDN(value)
+- groups = append(groups, cn)
+- }
+- labels["groups"] = groups
+-
+- return true, labels, nil
++ // Extract labels from the attribute values
++ labels, labelsExtractErr := la.getLabelsFromMap(entryAttrMap)
++ if labelsExtractErr != nil {
++ return false, nil, labelsExtractErr
+ }
+
+- return true, nil, nil
++ return true, labels, nil
+ }
+
+ func (la *LDAPAuth) bindReadOnlyUser(l *ldap.Conn) error {
+@@ -193,9 +188,9 @@ func (la *LDAPAuth) getFilter(account string) string {
+
+ //ldap search and return required attributes' value from searched entries
+ //default return entry's DN value if you leave attrs array empty
+-func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (map[string][]string, error) {
++func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, map[string][]string, error) {
+ if l == nil {
+- return nil, fmt.Errorf("No ldap connection!")
++ return "", nil, fmt.Errorf("No ldap connection!")
+ }
+ glog.V(2).Infof("Searching...basedDN:%s, filter:%s", *baseDN, *filter)
+ searchRequest := ldap.NewSearchRequest(
+@@ -206,38 +201,66 @@ func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, att
+ nil)
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+- return nil, err
++ return "", nil, err
+ }
+
+ if len(sr.Entries) == 0 {
+- return nil, nil // User does not exist
++ return "", nil, nil // User does not exist
+ } else if len(sr.Entries) > 1 {
+- return nil, fmt.Errorf("Too many entries returned.")
++ return "", nil, fmt.Errorf("Too many entries returned.")
+ }
+
+- result := make(map[string][]string)
++ attributes := make(map[string][]string)
++ var entryDn string
+ for _, entry := range sr.Entries {
+-
++ entryDn = entry.DN
+ if len(*attrs) == 0 {
+- glog.V(2).Infof("Entry DN = %s", entry.DN)
+- result["DN"] = []string{entry.DN}
++ glog.V(2).Infof("Entry DN = %s", entryDn)
+ } else {
+ for _, attr := range *attrs {
+- var values []string
+- if attr == "DN" {
+- // DN is excluded from attributes
+- values = []string{entry.DN}
+- } else {
+- values = entry.GetAttributeValues(attr)
+- }
+- valuesString := strings.Join(values, "\n")
+- glog.V(2).Infof("Entry %s = %s", attr, valuesString)
+- result[attr] = values
++ values := entry.GetAttributeValues(attr)
++ glog.V(2).Infof("Entry %s = %s", attr, strings.Join(values, "\n"))
++ attributes[attr] = values
+ }
+ }
+ }
+
+- return result, nil
++ return entryDn, attributes, nil
++}
++
++func (la *LDAPAuth) getLabelAttributes() ([]string, error) {
++ labelAttributes := make([]string, len(la.config.LabelMaps))
++ i := 0
++ for key, mapping := range la.config.LabelMaps {
++ if mapping.Attribute == "" {
++ return nil, fmt.Errorf("Label %s is missing 'attribute' to map from", key)
++ }
++ labelAttributes[i] = mapping.Attribute
++ i++
++ }
++ return labelAttributes, nil
++}
++
++func (la *LDAPAuth) getLabelsFromMap(attrMap map[string][]string) (map[string][]string, error) {
++ labels := make(map[string][]string)
++ for key, mapping := range la.config.LabelMaps {
++ if mapping.Attribute == "" {
++ return nil, fmt.Errorf("Label %s is missing 'attribute' to map from", key)
++ }
++
++ mappingValues := attrMap[mapping.Attribute]
++ if mappingValues != nil {
++ if mapping.ParseCN {
++ // shorten attribute to its common name
++ for i, value := range mappingValues {
++ cn := la.getCNFromDN(value)
++ mappingValues[i] = cn
++ }
++ }
++ labels[key] = mappingValues
++ }
++ }
++ return labels, nil
+ }
+
+ func (la *LDAPAuth) getCNFromDN(dn string) string {
+
+From cd37001980267a99a9faa19f1927891af63acb90 Mon Sep 17 00:00:00 2001
+From: Kevin <kcd83@users.noreply.github.com>
+Date: Tue, 28 Feb 2017 18:27:16 +1300
+Subject: [PATCH 3/3] Remove unused configuration fields, never implemented?
+
+---
+ auth_server/authn/ldap_auth.go | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/auth_server/authn/ldap_auth.go b/auth_server/authn/ldap_auth.go
+index 6f733a2..9c8bcb8 100644
+--- a/auth_server/authn/ldap_auth.go
++++ b/auth_server/authn/ldap_auth.go
+@@ -40,8 +40,6 @@ type LDAPAuthConfig struct {
+ BindDN string `yaml:"bind_dn,omitempty"`
+ BindPasswordFile string `yaml:"bind_password_file,omitempty"`
+ LabelMaps map[string]LabelMap `yaml:"labels,omitempty"`
+- GroupBaseDN string `yaml:"group_base_dn,omitempty"`
+- GroupFilter string `yaml:"group_filter,omitempty"`
+ }
+
+ type LDAPAuth struct {