Skip to content

Commit

Permalink
connector/ldap: treat attributes as case-insensitive all the way
Browse files Browse the repository at this point in the history
LDAP itself doesn't match attributes case-sensitively, so a query for

    (fOO=bar)

will return all the entries having `foo: bar`, regardless of how the
attribute name is defined in the schema.

However, the result entries we get will have the case according to what
the server returned. So, assuming the schema calls it `foo`, this is
what we're given.

Now, for certain attributes that are user-configurable -- NameAttr for
example -- this can cause trouble: the query returns the right results,
but the LDAP connector can't make sense of it as it's looking for an
attribute called `fOO`.

The real life case underlying this conundrum is Active Directory's
sAMAccountName.

Note that this is a bit of a workaround. Ideally, we'd use
`(*ldap.Entry).GetAttributes(string) []string` to access the attributes;
but until the case sensitivity issue is fixed there[1], changing the way
we read the results doesn't help us.

[1]: go-ldap/ldap#111

Signed-off-by: Stephan Renatus <[email protected]>
  • Loading branch information
srenatus committed Jun 19, 2018
1 parent 036e5d0 commit 73e5c74
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 6 deletions.
12 changes: 6 additions & 6 deletions connector/ldap/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io/ioutil"
"net"
"strings"

"gopkg.in/ldap.v2"

Expand Down Expand Up @@ -289,15 +290,14 @@ func (c *ldapConnector) do(ctx context.Context, f func(c *ldap.Conn) error) erro
}

func getAttrs(e ldap.Entry, name string) []string {
for _, a := range e.Attributes {
if a.Name != name {
continue
}
return a.Values
}
if name == "DN" {
return []string{e.DN}
}
for _, a := range e.Attributes {
if strings.EqualFold(a.Name, name) {
return a.Values
}
}
return nil
}

Expand Down
99 changes: 99 additions & 0 deletions connector/ldap/ldap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,105 @@ gidNumber: 1002
runTests(t, schema, connectLDAP, c, tests)
}

func TestCaseInsensitiveAttributeComparisons(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
# Groups are enumerated as part of the user entity instead of the members being
# a list on the group entity.
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: [email protected]
userpassword: foo
departmentNumber: 1000
departmentNumber: 1001
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: [email protected]
userpassword: bar
departmentNumber: 1000
departmentNumber: 1002
# Group definitions. Notice that they don't have any "member" field.
dn: ou=Groups,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: admins
gidNumber: 1000
dn: cn=developers,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: developers
gidNumber: 1001
dn: cn=designers,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: designers
gidNumber: 1002
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "CN" // different case than what LDAP returns
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=Groups,dc=example,dc=org"
c.GroupSearch.UserAttr = "departmentnumber" // different, too
c.GroupSearch.GroupAttr = "gidNumber"
c.GroupSearch.NameAttr = "cn"

tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "[email protected]",
EmailVerified: true,
Groups: []string{"admins", "developers"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
Username: "john",
Email: "[email protected]",
EmailVerified: true,
Groups: []string{"admins", "designers"},
},
},
}

runTests(t, schema, connectLDAP, c, tests)
}

func TestStartTLS(t *testing.T) {
schema := `
dn: dc=example,dc=org
Expand Down

0 comments on commit 73e5c74

Please sign in to comment.