From 8d718357dfa5a62f919e61cf620a862cae87e833 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Sun, 18 Nov 2018 10:37:50 -0800 Subject: [PATCH] find_dn_by_login: handle complex filters RFC4515 requires filters to be wrapped with parenthesis '(' and ')'. Over-wrapped filters are invalid! e.g. '((uid=x))' OpenLDAP permits simple filters to omit parenthesis entirely: e.g. 'uid=x' is automatically treated as '(uid=x)' The OpenLDAP behavior is taken as a given in many uses, which can lead to bad assumptions merging filters, because over-wrapped filters ARE still rejected. To cope with these cases, only wrap the incoming filter in parenthesis if it does NOT already have them. Signed-off-by: Robin H. Johnson --- ssh_ldap_pubkey/__init__.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ssh_ldap_pubkey/__init__.py b/ssh_ldap_pubkey/__init__.py index b89e866..9ac8c0c 100644 --- a/ssh_ldap_pubkey/__init__.py +++ b/ssh_ldap_pubkey/__init__.py @@ -220,7 +220,25 @@ def find_dn_by_login(self, login): ldap.LDAPError: """ conf = self.conf - filter_s = "(&(%s)(%s=%s))" % (conf.filter, conf.login_attr, login) + # RFC4515 requires filters to be wrapped with parenthesis '(' and ')'. + # Over-wrapped filters are invalid! e.g. '((uid=x))' + # + # OpenLDAP permits simple filters to omit parenthesis entirely: + # e.g. 'uid=x' is automatically treated as '(uid=x)' + # + # The OpenLDAP behavior is taken as a given in many uses, which can + # lead to bad assumptions merging filters, because over-wrapped filters + # ARE still rejected. + # + # To cope with these cases, only wrap the incoming filter in + # parenthesis if it does NOT already have them. + must_wrap = conf.filter[0] != '(' + filter_s = "(&%s%s%s(%s=%s))" % ( + '(' if must_wrap else '', + conf.filter, + ')' if must_wrap else '', + conf.login_attr, + login) result = self._conn.search_s(conf.base, conf.scope, filter_s, ['dn']) if not result: