From 59e9f296a4a2fa4e9f659a983b71f4aafd318116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Fri, 31 Jul 2020 17:31:50 +0200 Subject: [PATCH] fix LDAP substring startswith filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- .../unreleased/fix-startswith-queries.md | 5 ++ pkg/server/glauth/handler.go | 49 +++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 changelog/unreleased/fix-startswith-queries.md diff --git a/changelog/unreleased/fix-startswith-queries.md b/changelog/unreleased/fix-startswith-queries.md new file mode 100644 index 0000000000..eb9eacd1b5 --- /dev/null +++ b/changelog/unreleased/fix-startswith-queries.md @@ -0,0 +1,5 @@ +Bugfix: fix LDAP substring startswith filters + +Filters like `(mail=mar*)` are currentld not parsed correctly, but they are used when searching for recipients. This PR correctly converts them to odata filters like `startswith(mail,'mar')`. + +https://github.com/owncloud/ocis-glauth/pull/31 \ No newline at end of file diff --git a/pkg/server/glauth/handler.go b/pkg/server/glauth/handler.go index ac7ec863a0..b79d292b4a 100644 --- a/pkg/server/glauth/handler.go +++ b/pkg/server/glauth/handler.go @@ -303,7 +303,11 @@ func (h ocisHandler) mapGroups(groups []*accounts.Group) []*ldap.Entry { // "" not determined // "users" // "groups" -func parseFilter(f *ber.Packet) (qtype queryType, q string, code ldap.LDAPResultCode, err error) { +func parseFilter(f *ber.Packet) (queryType, string, ldap.LDAPResultCode, error) { + var qtype queryType + var q string + var code ldap.LDAPResultCode + var err error switch ldap.FilterMap[f.Tag] { case "Equality Match": if len(f.Children) != 2 { @@ -326,6 +330,8 @@ func parseFilter(f *ber.Packet) (qtype queryType, q string, code ldap.LDAPResult case "ownclouduuid": q = fmt.Sprintf("id eq '%s'", escapeValue(value)) case "cn", "uid": + // on_premises_sam_account_name is indexed using the lowercase analyzer in ocis-accounts + // TODO use "tolower(on_premises_sam_account_name) eq '%s'" to be clear about the case insensitive comparison q = fmt.Sprintf("on_premises_sam_account_name eq '%s'", escapeValue(value)) case "mail": q = fmt.Sprintf("mail eq '%s'", escapeValue(value)) @@ -349,8 +355,45 @@ func parseFilter(f *ber.Packet) (qtype queryType, q string, code ldap.LDAPResult code = ldap.LDAPResultUndefinedAttributeType err = fmt.Errorf("unrecognized assertion type '%s' in filter item", attribute) } + return qtype, q, code, err + case "Substrings": + if len(f.Children) != 2 { + return "", "", ldap.LDAPResultOperationsError, errors.New("substrings filter must have exactly two children") + } + attribute := strings.ToLower(f.Children[0].Value.(string)) + if len(f.Children[1].Children) != 1 { + return "", "", ldap.LDAPResultUnwillingToPerform, fmt.Errorf("substrings filter only supports prefix match") + } + value := f.Children[1].Children[0].Value.(string) - return + // replace attributes + switch attribute { + case "objectclass": + switch strings.ToLower(value) { + case "posixaccount", "shadowaccount", "users", "person", "inetorgperson", "organizationalperson": + qtype = usersQuery + case "posixgroup", "groups": + qtype = groupsQuery + default: + qtype = "" + } + case "ownclouduuid": + q = fmt.Sprintf("startswith(id,'%s')", escapeValue(value)) + case "cn", "uid": + // on_premises_sam_account_name is indexed using the lowercase analyzer in ocis-accounts + // TODO use "tolower(on_premises_sam_account_name) eq '%s'" to be clear about the case insensitive comparison + q = fmt.Sprintf("startswith(on_premises_sam_account_name,'%s')", escapeValue(value)) + case "mail": + q = fmt.Sprintf("startswith(mail,'%s')", escapeValue(value)) + case "displayname": + q = fmt.Sprintf("startswith(display_name,'%s')", escapeValue(value)) + case "description": + q = fmt.Sprintf("startswith(description,'%s')", escapeValue(value)) + default: + code = ldap.LDAPResultUndefinedAttributeType + err = fmt.Errorf("unrecognized assertion type '%s' in filter item", attribute) + } + return qtype, q, code, err case "And", "Or": subQueries := []string{} for i := range f.Children { @@ -383,7 +426,7 @@ func parseFilter(f *ber.Packet) (qtype queryType, q string, code ldap.LDAPResult } return qtype, q, code, nil } - return + return qtype, q, ldap.LDAPResultUnwillingToPerform, fmt.Errorf("%s filter not implemented", ldap.FilterMap[f.Tag]) } // escapeValue escapes all special characters in the value