Skip to content

Commit

Permalink
Split LDAP user filters
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
  • Loading branch information
butonic committed Jul 23, 2020
1 parent 7bc0cb7 commit 86c9db2
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
11 changes: 11 additions & 0 deletions changelog/unreleased/split-ldap-filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Enhancement: Split LDAP user filters

The current LDAP user filters only allow a single `%s` to be replaced with the relevant string. We moved to filter templates that can use the CS3 user id properties `{{.OpaqueId}}` and `{{.Idp}}`. Furthermore,
we introduced a new find filter that is used when searching for users. An example config would be
```
userfilter = "(&(objectclass=posixAccount)(|(ownclouduuid={{.OpaqueId}})(cn={{.OpaqueId}})))"
findfilter = "(&(objectclass=posixAccount)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))"
```
As you can see the userfilter is used to lookup a single user, whereas the findfilter is for a broader search, e.g. used when searching for share recipients.

https://github.com/cs3org/reva/pull/996
65 changes: 56 additions & 9 deletions pkg/user/manager/ldap/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@
package ldap

import (
"bytes"
"context"
"crypto/tls"
"fmt"
"strings"
"text/template"

"github.com/Masterminds/sprig"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
Expand All @@ -41,8 +45,9 @@ type manager struct {
hostname string
port int
baseDN string
userfilter string
groupfilter string
userfilter *template.Template
findfilter string
groupfilter *template.Template
bindUsername string
bindPassword string
idp string
Expand All @@ -54,6 +59,7 @@ type config struct {
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"`
Expand Down Expand Up @@ -97,17 +103,36 @@ func New(m map[string]interface{}) (user.Manager, error) {
return nil, err
}

return &manager{
// backwards compatibility
c.UserFilter = strings.ReplaceAll(c.UserFilter, "%s", "{{.OpaqueId}}")
if c.FindFilter == "" {
c.FindFilter = c.UserFilter
}
c.GroupFilter = strings.ReplaceAll(c.GroupFilter, "%s", "{{.OpaqueId}}")

mgr := &manager{
hostname: c.Hostname,
port: c.Port,
baseDN: c.BaseDN,
userfilter: c.UserFilter,
groupfilter: c.GroupFilter,
findfilter: c.FindFilter,
bindUsername: c.BindUsername,
bindPassword: c.BindPassword,
idp: c.Idp,
schema: c.Schema,
}, nil
}

mgr.userfilter, err = template.New("uf").Funcs(sprig.TxtFuncMap()).Parse(c.UserFilter)
if err != nil {
err := errors.Wrap(err, fmt.Sprintf("error parsing userfilter tpl:%s", c.UserFilter))
panic(err)
}
mgr.groupfilter, err = template.New("gf").Funcs(sprig.TxtFuncMap()).Parse(c.GroupFilter)
if err != nil {
err := errors.Wrap(err, fmt.Sprintf("error parsing groupfilter tpl:%s", c.GroupFilter))
panic(err)
}

return mgr, nil
}

func (m *manager) GetUser(ctx context.Context, uid *userpb.UserId) (*userpb.User, error) {
Expand All @@ -128,7 +153,7 @@ func (m *manager) GetUser(ctx context.Context, uid *userpb.UserId) (*userpb.User
searchRequest := ldap.NewSearchRequest(
m.baseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(m.userfilter, uid.OpaqueId), // TODO this is screaming for errors if filter contains >1 %s
m.getUserFilter(uid),
[]string{m.schema.DN, m.schema.UID, m.schema.Mail, m.schema.DisplayName},
nil,
)
Expand Down Expand Up @@ -180,7 +205,7 @@ func (m *manager) FindUsers(ctx context.Context, query string) ([]*userpb.User,
searchRequest := ldap.NewSearchRequest(
m.baseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(m.userfilter, query), // TODO this is screaming for errors if filter contains >1 %s
m.getFindFilter(query),
[]string{m.schema.DN, m.schema.UID, m.schema.Mail, m.schema.DisplayName},
nil,
)
Expand Down Expand Up @@ -231,7 +256,7 @@ func (m *manager) GetUserGroups(ctx context.Context, uid *userpb.UserId) ([]stri
searchRequest := ldap.NewSearchRequest(
m.baseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(m.groupfilter, uid.OpaqueId), // TODO this is screaming for errors if filter contains >1 %s
m.getGroupFilter(uid),
[]string{m.schema.CN},
nil,
)
Expand Down Expand Up @@ -264,3 +289,25 @@ func (m *manager) IsInGroup(ctx context.Context, uid *userpb.UserId, group strin

return false, nil
}

func (m *manager) getUserFilter(uid *userpb.UserId) string {
b := bytes.Buffer{}
if err := m.userfilter.Execute(&b, uid); err != nil {
err := errors.Wrap(err, fmt.Sprintf("error executing user template: userid:%+v", uid))
panic(err)
}
return b.String()
}

func (m *manager) getFindFilter(query string) string {
return strings.ReplaceAll(m.findfilter, "{{query}}", query)
}

func (m *manager) getGroupFilter(uid *userpb.UserId) string {
b := bytes.Buffer{}
if err := m.groupfilter.Execute(&b, uid); err != nil {
err := errors.Wrap(err, fmt.Sprintf("error executing group template: userid:%+v", uid))
panic(err)
}
return b.String()
}

0 comments on commit 86c9db2

Please sign in to comment.