@@ -133,7 +133,7 @@ def load_users_and_groups(self, groups, extended_attributes, all_users):
133
133
if not group_dn :
134
134
self .logger .warning ("No group found for: %s" , group )
135
135
continue
136
- group_member_subfilter = group_member_filter_format . format ( group_dn = group_dn )
136
+ group_member_subfilter = self . format_ldap_query_string ( group_member_filter_format , group_dn = group_dn )
137
137
if not group_member_subfilter .startswith ('(' ):
138
138
group_member_subfilter = six .text_type ('(' ) + group_member_subfilter + six .text_type (')' )
139
139
user_subfilter = all_users_filter
@@ -178,8 +178,9 @@ def find_ldap_group_dn(self, group):
178
178
base_dn = six .text_type (options ['base_dn' ])
179
179
group_filter_format = six .text_type (options ['group_filter_format' ])
180
180
try :
181
+ filter_string = self .format_ldap_query_string (group_filter_format , group = group )
181
182
res = connection .search_s (base_dn , ldap .SCOPE_SUBTREE ,
182
- filterstr = group_filter_format . format ( group = group ) , attrsonly = 1 )
183
+ filterstr = filter_string , attrsonly = 1 )
183
184
except Exception as e :
184
185
raise AssertionException ('Unexpected LDAP failure reading group info: %s' % e )
185
186
group_dn = None
@@ -324,6 +325,34 @@ def iter_search_result(self, base_dn, scope, filter_string, attributes):
324
325
connection .abandon (msgid )
325
326
raise
326
327
328
+ @staticmethod
329
+ def format_ldap_query_string (query , ** kwargs ):
330
+ """
331
+ Escape LDAP special characters that may appear in injected query strings
332
+ Should be used with any string that will be injected into an LDAP query.
333
+ :param query:
334
+ :param kwargs:
335
+ :return:
336
+ """
337
+ # See http://www.rfc-editor.org/rfc/rfc4515.txt
338
+ escape_chars = six .text_type ('*()\\ &|<>~!:' )
339
+ escaped_args = {}
340
+ # kwargs is a dict that would normally be passed to string.format
341
+ for k , v in six .iteritems (kwargs ):
342
+ # LDAP special characters are escaped in the general format '\' + hex(char)
343
+ # we need to run through the string char by char and if the char exists in
344
+ # the escape_char list, get the ord of it (decimal ascii value), convert it to hex, and
345
+ # replace the '0x' with '\'
346
+ escaped_list = []
347
+ for c in v :
348
+ if c in escape_chars :
349
+ replace = six .text_type (hex (ord (c ))).replace ('0x' , '\\ ' )
350
+ escaped_list .append (replace )
351
+ else :
352
+ escaped_list .append (c )
353
+ escaped_args [k ] = six .text_type ('' ).join (escaped_list )
354
+ return query .format (** escaped_args )
355
+
327
356
328
357
class LDAPValueFormatter (object ):
329
358
encoding = 'utf8'
0 commit comments