Skip to content

Commit

Permalink
Implement GetUserByClaim for LDAP user driver
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
  • Loading branch information
butonic committed Aug 13, 2020
1 parent f325194 commit b699c39
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 12 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/ldap-get-by-claim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Implement GetUserByClaim for LDAP user driver

The LDAP user driver can now fetch users by a single claim / attribute. Use an `attributefilter` like `(&(objectclass=posixAccount)({{attr}}={{value}}))` in the driver section.

https://github.com/cs3org/reva/pull/1088
102 changes: 90 additions & 12 deletions pkg/user/manager/ldap/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ type manager struct {
}

type config struct {
Hostname string `mapstructure:"hostname"`
Port int `mapstructure:"port"`
BaseDN string `mapstructure:"base_dn"`
UserFilter string `mapstructure:"userfilter"`
FindFilter string `mapstructure:"findfilter"`
GroupFilter string `mapstructure:"groupfilter"`
BindUsername string `mapstructure:"bind_username"`
BindPassword string `mapstructure:"bind_password"`
Idp string `mapstructure:"idp"`
Schema attributes `mapstructure:"schema"`
Hostname string `mapstructure:"hostname"`
Port int `mapstructure:"port"`
BaseDN string `mapstructure:"base_dn"`
UserFilter string `mapstructure:"userfilter"`
AttributeFilter string `mapstructure:"attributefilter"`
FindFilter string `mapstructure:"findfilter"`
GroupFilter string `mapstructure:"groupfilter"`
BindUsername string `mapstructure:"bind_username"`
BindPassword string `mapstructure:"bind_password"`
Idp string `mapstructure:"idp"`
Schema attributes `mapstructure:"schema"`
}

type attributes struct {
Expand All @@ -71,6 +72,10 @@ type attributes struct {
Mail string `mapstructure:"mail"`
// Displayname is the Human readable name, e.g. `Albert Einstein`
DisplayName string `mapstructure:"displayName"`
// UIDNumber is a numeric id that maps to a filesystem uid, eg. 123546
UIDNumber string `mapstructure:"uidNumber"`
// GIDNumber is a numeric id that maps to a filesystem gid, eg. 654321
GIDNumber string `mapstructure:"gidNumber"`
}

// Default attributes (Active Directory)
Expand All @@ -80,6 +85,8 @@ var ldapDefaults = attributes{
CN: "cn",
Mail: "mail",
DisplayName: "displayName",
UIDNumber: "uidNumber",
GIDNumber: "gidNumber",
}

func parseConfig(m map[string]interface{}) (*config, error) {
Expand Down Expand Up @@ -179,8 +186,74 @@ func (m *manager) GetUser(ctx context.Context, uid *userpb.UserId) (*userpb.User
return u, nil
}

func (m *manager) GetUserByClaim(ctx context.Context, field, claim string) (*userpb.User, error) {
return nil, errtypes.NotSupported("ldap: looking up user by specific field not supported")
func (m *manager) GetUserByClaim(ctx context.Context, claim, value string) (*userpb.User, error) {
// TODO align supported claims with rest driver and the others, maybe refactor into common mapping
switch claim {
case "mail":
claim = m.c.Schema.Mail
case "uid":
claim = m.c.Schema.UIDNumber
case "gid":
claim = m.c.Schema.GIDNumber
case "username":
claim = m.c.Schema.CN
case "userid":
claim = m.c.Schema.UID
default:
return nil, errors.New("ldap: invalid field " + claim)
}

log := appctx.GetLogger(ctx)
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", m.c.Hostname, m.c.Port), &tls.Config{InsecureSkipVerify: true})
if err != nil {
return nil, err
}
defer l.Close()

// First bind with a read only user
err = l.Bind(m.c.BindUsername, m.c.BindPassword)
if err != nil {
return nil, err
}

// Search for the given clientID
searchRequest := ldap.NewSearchRequest(
m.c.BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
m.getAttributeFilter(claim, value),
[]string{m.c.Schema.DN, m.c.Schema.UID, m.c.Schema.CN, m.c.Schema.Mail, m.c.Schema.DisplayName},
nil,
)

sr, err := l.Search(searchRequest)
if err != nil {
return nil, err
}

if len(sr.Entries) != 1 {
return nil, errtypes.NotFound(claim + ":" + value)
}

log.Debug().Interface("entries", sr.Entries).Msg("entries")

id := &userpb.UserId{
Idp: m.c.Idp,
OpaqueId: sr.Entries[0].GetEqualFoldAttributeValue(m.c.Schema.UID),
}
groups, err := m.GetUserGroups(ctx, id)
if err != nil {
return nil, err
}
u := &userpb.User{
Id: id,
Username: sr.Entries[0].GetEqualFoldAttributeValue(m.c.Schema.CN),
Groups: groups,
Mail: sr.Entries[0].GetEqualFoldAttributeValue(m.c.Schema.Mail),
DisplayName: sr.Entries[0].GetEqualFoldAttributeValue(m.c.Schema.DisplayName),
}

return u, nil

}

func (m *manager) FindUsers(ctx context.Context, query string) ([]*userpb.User, error) {
Expand Down Expand Up @@ -298,6 +371,11 @@ func (m *manager) getUserFilter(uid *userpb.UserId) string {
return b.String()
}

func (m *manager) getAttributeFilter(attribute, value string) string {
attr := strings.ReplaceAll(m.c.AttributeFilter, "{{attr}}", attribute)
return strings.ReplaceAll(attr, "{{value}}", value)
}

func (m *manager) getFindFilter(query string) string {
return strings.ReplaceAll(m.c.FindFilter, "{{query}}", query)
}
Expand Down

0 comments on commit b699c39

Please sign in to comment.