connector/ldap: backward compatibility with single user to group mapping
Signed-off-by: Vitaliy Dmitriev <vi7alya@gmail.com>
This commit is contained in:
parent
f2e7823db9
commit
e20a795a2a
2 changed files with 128 additions and 2 deletions
|
@ -134,6 +134,12 @@ type Config struct {
|
||||||
|
|
||||||
Scope string `json:"scope"` // Defaults to "sub"
|
Scope string `json:"scope"` // Defaults to "sub"
|
||||||
|
|
||||||
|
// DEPRECATED config options. Those are left for backward compatibility.
|
||||||
|
// See "UserMatchers" below for the current group to user matching implementation
|
||||||
|
// TODO: should be eventually removed from the code
|
||||||
|
UserAttr string `json:"userAttr"`
|
||||||
|
GroupAttr string `json:"groupAttr"`
|
||||||
|
|
||||||
// Array of the field pairs used to match a user to a group.
|
// Array of the field pairs used to match a user to a group.
|
||||||
// See the "UserMatcher" struct for the exact field names
|
// See the "UserMatcher" struct for the exact field names
|
||||||
//
|
//
|
||||||
|
@ -175,6 +181,23 @@ func parseScope(s string) (int, bool) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build a list of group attr name to user attr value matchers.
|
||||||
|
// Function exists here to allow backward compatibility between old and new
|
||||||
|
// group to user matching implementations.
|
||||||
|
// See "Config.GroupSearch.UserMatchers" comments for the details
|
||||||
|
func (c *ldapConnector) userMatchers() []UserMatcher {
|
||||||
|
if len(c.GroupSearch.UserMatchers) > 0 && c.GroupSearch.UserMatchers[0].UserAttr != "" {
|
||||||
|
return c.GroupSearch.UserMatchers[:]
|
||||||
|
} else {
|
||||||
|
return []UserMatcher{
|
||||||
|
{
|
||||||
|
UserAttr: c.GroupSearch.UserAttr,
|
||||||
|
GroupAttr: c.GroupSearch.GroupAttr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Open returns an authentication strategy using LDAP.
|
// Open returns an authentication strategy using LDAP.
|
||||||
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
|
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
|
||||||
conn, err := c.OpenConnector(logger)
|
conn, err := c.OpenConnector(logger)
|
||||||
|
@ -392,7 +415,7 @@ func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.E
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, matcher := range c.GroupSearch.UserMatchers {
|
for _, matcher := range c.userMatchers() {
|
||||||
req.Attributes = append(req.Attributes, matcher.UserAttr)
|
req.Attributes = append(req.Attributes, matcher.UserAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +572,7 @@ func (c *ldapConnector) groups(ctx context.Context, user ldap.Entry) ([]string,
|
||||||
}
|
}
|
||||||
|
|
||||||
var groups []*ldap.Entry
|
var groups []*ldap.Entry
|
||||||
for _, matcher := range c.GroupSearch.UserMatchers {
|
for _, matcher := range c.userMatchers() {
|
||||||
for _, attr := range getAttrs(user, matcher.UserAttr) {
|
for _, attr := range getAttrs(user, matcher.UserAttr) {
|
||||||
filter := fmt.Sprintf("(%s=%s)", matcher.GroupAttr, ldap.EscapeFilter(attr))
|
filter := fmt.Sprintf("(%s=%s)", matcher.GroupAttr, ldap.EscapeFilter(attr))
|
||||||
if c.GroupSearch.Filter != "" {
|
if c.GroupSearch.Filter != "" {
|
||||||
|
|
|
@ -676,6 +676,109 @@ memberUid: janedoe
|
||||||
runTests(t, schema, connectLDAP, c, tests)
|
runTests(t, schema, connectLDAP, c, tests)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test deprecated group to user matching implementation
|
||||||
|
// which was left for backward compatibility.
|
||||||
|
// See "Config.GroupSearch.UserMatchers" comments for the details
|
||||||
|
func TestDeprecatedGroupToUserMatcher(t *testing.T) {
|
||||||
|
schema := `
|
||||||
|
dn: ou=People,dc=example,dc=org
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: People
|
||||||
|
|
||||||
|
dn: cn=jane,ou=People,dc=example,dc=org
|
||||||
|
objectClass: person
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
sn: doe
|
||||||
|
cn: jane
|
||||||
|
mail: janedoe@example.com
|
||||||
|
userpassword: foo
|
||||||
|
|
||||||
|
dn: cn=john,ou=People,dc=example,dc=org
|
||||||
|
objectClass: person
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
sn: doe
|
||||||
|
cn: john
|
||||||
|
mail: johndoe@example.com
|
||||||
|
userpassword: bar
|
||||||
|
|
||||||
|
# Group definitions.
|
||||||
|
|
||||||
|
dn: ou=Seattle,dc=example,dc=org
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: Seattle
|
||||||
|
|
||||||
|
dn: ou=Portland,dc=example,dc=org
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: Portland
|
||||||
|
|
||||||
|
dn: ou=Groups,ou=Seattle,dc=example,dc=org
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: Groups
|
||||||
|
|
||||||
|
dn: ou=Groups,ou=Portland,dc=example,dc=org
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: Groups
|
||||||
|
|
||||||
|
dn: cn=qa,ou=Groups,ou=Portland,dc=example,dc=org
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: qa
|
||||||
|
member: cn=john,ou=People,dc=example,dc=org
|
||||||
|
|
||||||
|
dn: cn=admins,ou=Groups,ou=Seattle,dc=example,dc=org
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: admins
|
||||||
|
member: cn=john,ou=People,dc=example,dc=org
|
||||||
|
member: cn=jane,ou=People,dc=example,dc=org
|
||||||
|
|
||||||
|
dn: cn=developers,ou=Groups,ou=Seattle,dc=example,dc=org
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: developers
|
||||||
|
member: cn=jane,ou=People,dc=example,dc=org
|
||||||
|
`
|
||||||
|
c := &Config{}
|
||||||
|
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
|
||||||
|
c.UserSearch.NameAttr = "cn"
|
||||||
|
c.UserSearch.EmailAttr = "mail"
|
||||||
|
c.UserSearch.IDAttr = "DN"
|
||||||
|
c.UserSearch.Username = "cn"
|
||||||
|
c.GroupSearch.BaseDN = "dc=example,dc=org"
|
||||||
|
c.GroupSearch.UserAttr = "DN"
|
||||||
|
c.GroupSearch.GroupAttr = "member"
|
||||||
|
c.GroupSearch.NameAttr = "cn"
|
||||||
|
c.GroupSearch.Filter = "(ou:dn:=Seattle)" // ignore other groups
|
||||||
|
|
||||||
|
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: "janedoe@example.com",
|
||||||
|
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: "johndoe@example.com",
|
||||||
|
EmailVerified: true,
|
||||||
|
Groups: []string{"admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runTests(t, schema, connectLDAP, c, tests)
|
||||||
|
}
|
||||||
|
|
||||||
func TestStartTLS(t *testing.T) {
|
func TestStartTLS(t *testing.T) {
|
||||||
schema := `
|
schema := `
|
||||||
dn: ou=People,dc=example,dc=org
|
dn: ou=People,dc=example,dc=org
|
||||||
|
|
Reference in a new issue