def _match_equal_to(search_base, attribute, value, candidates): matches = list() match_using_regex = False if "*" in value: match_using_regex = True #regex = check_escape(value) regex = value.replace('*', '.*') regex = "^{0}$".format(regex) for entry in candidates: dn = entry.get("dn") if not attribute in entry.get("attributes") \ or not dn.endswith(search_base): continue values_from_directory = entry.get("attributes").get(attribute) if isinstance(values_from_directory, list): for item in values_from_directory: if attribute == "objectGUID": item = escape_bytes(item) if match_using_regex: m = re.match(regex, str(item), re.I) if m: entry["type"] = "searchResEntry" matches.append(entry) else: if item == value: entry["type"] = "searchResEntry" matches.append(entry) else: if attribute == "objectGUID": values_from_directory = escape_bytes(values_from_directory) if match_using_regex: m = re.match(regex, str(values_from_directory), re.I) if m: entry["type"] = "searchResEntry" matches.append(entry) else: if str(value) == str(values_from_directory): entry["type"] = "searchResEntry" matches.append(entry) return matches
def test_search_exact_match_with_parentheses_in_filter(self): self.delete_at_teardown.append( add_user(self.connection, testcase_id, '(search)-3', attributes={'givenName': 'givenname-3'})) result = self.connection.search( search_base=test_base, search_filter='(&(' + test_name_attr + '=' + testcase_id + '*)(' + test_name_attr + '=*' + escape_bytes(')') + '*))', attributes=[test_name_attr, 'sn']) if not self.connection.strategy.sync: response, _ = self.connection.get_response(result) json_response = self.connection.response_to_json( search_result=response) else: json_response = self.connection.response_to_json() json_entries = json.loads(json_response)['entries'] self.assertEqual(len(json_entries), 1) if test_server_type == 'AD': self.assertEqual(json_entries[0]['attributes'][test_name_attr], testcase_id + '(search)-3') else: self.assertEqual(json_entries[0]['attributes'][test_name_attr][0], testcase_id + '(search)-3')
def get_user(self, user_id): from .models import PS1User """ Get's The user object and attached ldap_user data. Will create the database entry if required. Keyword arguments: user_id -- a string or UUID object of samba4 objectGUID of a user. """ try: guid = uuid.UUID(str(user_id)) except ValueError: # Happens when we get passed an invalid or outdated user_id return None try: user = PS1User.objects.get(object_guid=str(guid)) except PS1User.DoesNotExist: filter_string = '(objectGUID={})'.format( escape_bytes(guid.bytes_le)) with get_ldap_connection() as c: c.search(settings.AD_BASEDN, filter_string, LEVEL) user_dn = c.response[0]['dn'] user = PS1User(object_guid=str(guid)) user.save() return user
def _getDN(self, userId): """ This function returns the DN of a userId. Therefor it evaluates the self.uidtype. :param userId: The userid of a user :type userId: string :return: The DN of the object. """ dn = "" if self.uidtype.lower() == "dn": dn = userId else: if self.uidtype == "objectGUID": userId = uuid.UUID("{{{0!s}}}".format(userId)).bytes_le userId = escape_bytes(userId) # get the DN for the Object self._bind() filter = "(&{0!s}({1!s}={2!s}))".format(self.searchfilter, self.uidtype, userId) self.l.search(search_base=self.basedn, search_scope=self.scope, search_filter=filter, attributes=self.userinfo.values()) r = self.l.response r = self._trim_result(r) if len(r) > 1: # pragma: no cover raise Exception("Found more than one object for uid {0!r}".format(userId)) if len(r) == 1: dn = r[0].get("dn") return dn
def test_search_string_guid(self): self.delete_at_teardown.append( add_user(self.connection, testcase_id, 'sea-16', attributes={'givenName': testcase_id + 'givenname-16'})) if test_server_type == 'EDIR': status, result, response, request = get_response_values( self.connection.search(search_base=test_base, search_filter='(givenname=' + testcase_id + 'givenname-16)', attributes=[ test_name_attr, 'sn', 'guid' ]), self.connection) elif test_server_type == 'AD': # not tested on AD yet status, result, response, request = get_response_values( self.connection.search(search_base=test_base, search_filter='(givenname=' + testcase_id + 'givenname-16)', attributes=[ test_name_attr, 'sn', 'objectGuid' ]), self.connection) else: # not tested on other kind of servers return self.assertEqual(result['description'], 'success') self.assertEqual(len(response), 1) if test_server_type == 'EDIR': if self.connection.check_names: status, result, response, request = get_response_values( self.connection.search( search_base=test_base, search_filter='(guid=' + response[0]['attributes']['guid'] + ')', attributes=[test_name_attr, 'sn']), self.connection) else: status, result, response, request = get_response_values( self.connection.search( search_base=test_base, search_filter='(guid=' + escape_bytes( response[0]['raw_attributes']['guid'][0]) + ')', attributes=[test_name_attr, 'sn']), self.connection) elif test_server_type == 'AD': # not tested on AD yet status, result, response, request = get_response_values( self.connection.search( search_base=test_base, search_filter='(objectguid=' + response[0]['attributes']['objectguid'] + ')', attributes=[test_name_attr, 'sn']), self.connection) self.assertEqual(result['description'], 'success') self.assertEqual(len(response), 1) if test_server_type == 'EDIR': self.assertEqual(response[0]['attributes'][test_name_attr][0], testcase_id + 'sea-16') elif test_server_type == 'AD': self.assertEqual(response[0]['attributes'][test_name_attr], testcase_id + 'sea-16')
def get_ldap_group_membership(self, user_dn): """Retrieve django group ids that this user DN is a member of.""" if not hasattr(self, '_group_cache'): r = LDAPGroup.objects.all().values_list('distinguished_name', 'obj') self._group_cache = dict(r) logger.debug( 'Retrieving groups that {} is a member of'.format(user_dn)) ldap_groups = self.smart_ldap_searcher.search( self.group_base, self.group_membership_filter.format(user_dn=escape_bytes(user_dn)), ldap3.SEARCH_SCOPE_WHOLE_SUBTREE, None) return (self._group_cache.get(i['dn']) for i in ldap_groups if i.get('dn'))
def test_search_exact_match_with_parentheses_in_filter(self): self.delete_at_teardown.append( add_user(self.connection, testcase_id, '(search)-10', attributes={'givenName': 'givenname-10'})) status, result, response, request = get_response_values( self.connection.search( search_base=test_base, search_filter='(' + test_name_attr + '=' + testcase_id + '*' + escape_bytes(')') + '*)', attributes=[test_name_attr, 'sn']), self.connection) entries = self.connection._get_entries(response, request) self.assertEqual(result['description'], 'success') self.assertEqual(len(entries), 1) self.assertEqual(entries[0][test_name_attr][0], testcase_id + '(search)-10')
def ldap_user(self): if hasattr(self, '_ldap_user'): return self._ldap_user self._ldap_user = cache.get(self.object_guid) if not self._ldap_user: guid = uuid.UUID(self.object_guid) # certain byte sequences contain printable character that can # potentially be parseable by the query string. Escape each byte as # hex to make sure this doesn't happen. #restrung = ''.join(['\\%02x' % ord(x) for x in guid.bytes_le]) filter_string = '(objectGUID={})'.format(escape_bytes(guid.bytes_le)) with get_ldap_connection() as c: c.search(settings.AD_BASEDN, filter_string, LEVEL, attributes = ALL_ATTRIBUTES) result = c.response if len(result) > 0: self._ldap_user = result[0]['attributes'] cache.set(self.object_guid, self._ldap_user, 24 * 60 * 60 * 70) return self._ldap_user
def test_search_exact_match_with_parentheses_in_filter(self): self.delete_at_teardown.append( add_user(self.connection, testcase_id, '(search)-10', attributes={'givenName': 'givenname-10'})) result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=' + testcase_id + '*' + escape_bytes(')') + '*)', attributes=[test_name_attr, 'sn']) if not self.connection.strategy.sync: response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertEqual(result['description'], 'success') self.assertEqual(len(response), 1) self.assertEqual(response[0]['attributes'][test_name_attr][0], testcase_id + '(search)-10')
def test_search_exact_match_with_escaped_parentheses_in_filter(self): self.delete_at_teardown.append( add_user(self.connection, testcase_id, '(s)-12', attributes={'givenName': 'givenname-12'})) status, result, response, request = get_response_values( self.connection.search( search_base=test_base, search_filter='(' + test_name_attr + '=' + testcase_id + '*' + escape_bytes(')') + '*)', attributes=[test_name_attr, 'sn']), self.connection) self.assertEqual(result['description'], 'success') self.assertEqual(len(response), 1) if test_server_type == 'AD': self.assertEqual(response[0]['attributes'][test_name_attr], testcase_id + '(s)-12') else: self.assertEqual(response[0]['attributes'][test_name_attr][0], testcase_id + '(s)-12')
def getUserInfo(self, userId): """ This function returns all user info for a given userid/object. :param userId: The userid of the object :type userId: string :return: A dictionary with the keys defined in self.userinfo :rtype: dict """ ret = {} self._bind() if self.uidtype.lower() == "dn": # encode utf8, so that also german ulauts work in the DN self.l.search(search_base=to_utf8(userId), search_scope=self.scope, search_filter="(&" + self.searchfilter + ")", attributes=self.userinfo.values()) else: if self.uidtype == "objectGUID": userId = uuid.UUID("{{{0!s}}}".format(userId)).bytes_le userId = escape_bytes(userId) filter = "(&{0!s}({1!s}={2!s}))".format(self.searchfilter, self.uidtype, userId) self.l.search(search_base=self.basedn, search_scope=self.scope, search_filter=filter, attributes=self.userinfo.values()) r = self.l.response r = self._trim_result(r) if len(r) > 1: # pragma: no cover raise Exception( "Found more than one object for uid {0!r}".format(userId)) for entry in r: attributes = entry.get("attributes") ret = self._ldap_attributes_to_user_object(attributes) return ret
def getUserInfo(self, userId): """ This function returns all user info for a given userid/object. :param userId: The userid of the object :type userId: string :return: A dictionary with the keys defined in self.userinfo :rtype: dict """ ret = {} self._bind() if self.uidtype.lower() == "dn": # encode utf8, so that also german ulauts work in the DN self.l.search(search_base=to_utf8(userId), search_scope=self.scope, search_filter="(&" + self.searchfilter + ")", attributes=self.userinfo.values()) else: if self.uidtype == "objectGUID": userId = uuid.UUID("{{{0!s}}}".format(userId)).bytes_le userId = escape_bytes(userId) filter = "(&{0!s}({1!s}={2!s}))".format(self.searchfilter, self.uidtype, userId) self.l.search(search_base=self.basedn, search_scope=self.scope, search_filter=filter, attributes=self.userinfo.values()) r = self.l.response r = self._trim_result(r) if len(r) > 1: # pragma: no cover raise Exception("Found more than one object for uid {0!r}".format(userId)) for entry in r: attributes = entry.get("attributes") ret = self._ldap_attributes_to_user_object(attributes) return ret
def ldap_user(self): if hasattr(self, '_ldap_user'): return self._ldap_user self._ldap_user = cache.get(self.object_guid) if not self._ldap_user: guid = uuid.UUID(self.object_guid) # certain byte sequences contain printable character that can # potentially be parseable by the query string. Escape each byte as # hex to make sure this doesn't happen. #restrung = ''.join(['\\%02x' % ord(x) for x in guid.bytes_le]) filter_string = '(objectGUID={})'.format( escape_bytes(guid.bytes_le)) with get_ldap_connection() as c: c.search(settings.AD_BASEDN, filter_string, LEVEL, attributes=ALL_ATTRIBUTES) result = c.response if len(result) > 0: self._ldap_user = result[0]['attributes'] cache.set(self.object_guid, self._ldap_user, 24 * 60 * 60 * 70) return self._ldap_user
def get_user(self, user_id): from .models import PS1User """ Get's The user object and attached ldap_user data. Will create the database entry if required. Keyword arguments: user_id -- a string or UUID object of samba4 objectGUID of a user. """ try: guid = uuid.UUID(str(user_id)) except ValueError: # Happens when we get passed an invalid or outdated user_id return None try: user = PS1User.objects.get(object_guid=str(guid)) except PS1User.DoesNotExist: filter_string = '(objectGUID={})'.format(escape_bytes(guid.bytes_le)) with get_ldap_connection() as c: c.search(settings.AD_BASEDN, filter_string, LEVEL) user_dn = c.response[0]['dn'] user = PS1User(object_guid=str(guid)) user.save() return user
def escaped(query): return escape_bytes(query)
def _convert_objectGUID(item): item = uuid.UUID("{{{0!s}}}".format(item)).bytes_le item = escape_bytes(item) return item
def get_ldap_group_membership(self, user_dn): """Retrieve django group ids that this user DN is a member of.""" if not hasattr(self, '_group_cache'): r = LDAPGroup.objects.all().values_list('distinguished_name', 'obj') self._group_cache = dict(r) logger.debug('Retrieving groups that {} is a member of'.format(user_dn)) ldap_groups = self.smart_ldap_searcher.search(self.group_base, self.group_membership_filter.format(user_dn=escape_bytes(user_dn)), ldap3.SEARCH_SCOPE_WHOLE_SUBTREE, None) return (self._group_cache.get(i['dn']) for i in ldap_groups if i.get('dn'))
def guid_to_search(cls, guid): return escape_bytes(uuid.UUID(guid).bytes_le)
def test_search_exact_match_with_parentheses_in_filter(self): result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=*' + escape_bytes(')') + '*)', attributes=[test_name_attr, 'sn']) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertEqual(result['description'], 'success') self.assertEqual(len(response), 1) self.assertEqual(response[0]['attributes']['cn'][0], 'test-search-(parentheses)')
def test_search_exact_match_with_parentheses_in_filter(self): self.delete_at_teardown.append(add_user(self.connection, testcase_id, '(search)-3', attributes={'givenName': 'givenname-3'})) result = self.connection.search(search_base=test_base, search_filter='(&(' + test_name_attr + '=' + testcase_id + '*)(' + test_name_attr + '=*' + escape_bytes(')') + '*))', attributes=[test_name_attr, 'sn']) if not self.connection.strategy.sync: response, _ = self.connection.get_response(result) json_response = self.connection.response_to_json(search_result=response) else: json_response = self.connection.response_to_json() json_entries = json.loads(json_response)['entries'] self.assertEqual(len(json_entries), 1) if test_server_type == 'AD': self.assertEqual(json_entries[0]['attributes'][test_name_attr], testcase_id + '(search)-3') else: self.assertEqual(json_entries[0]['attributes'][test_name_attr][0], testcase_id + '(search)-3')
def test_search_exact_match_with_parentheses_in_filter(self): self.delete_at_teardown.append(add_user(self.connection, testcase_id, '(search)-10', attributes={'givenName': 'givenname-10'})) result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=' + testcase_id + '*' + escape_bytes(')') + '*)', attributes=[test_name_attr, 'sn']) if not self.connection.strategy.sync: response, result = self.connection.get_response(result) entries = self.connection._get_entries(response) else: result = self.connection.result entries = self.connection.entries self.assertEqual(result['description'], 'success') self.assertEqual(len(entries), 1) self.assertEqual(entries[0][test_name_attr][0], testcase_id + '(search)-10')
MY_BASE = 'cn=Users, dc=ad2012, dc=LAB' MY_ADMIN = 'cn=Giovanni, cn=Users, dc=AD2012, dc=LAB' MY_PASSWORD = '******' MY_USER = '******' # establish a connection to the AD Server print('Trying to connect to ' + MY_SERVER + ' with user ' + MY_ADMIN) s = Server(MY_SERVER, use_ssl=True) c = Connection(s, MY_ADMIN, MY_PASSWORD) if c.bind(): print('Searching for object GUID for user ' + MY_USER) if c.search(MY_BASE, '(cn=%s)' % MY_USER, attributes=['objectGuid']): print('Entry ' + c.response[0]['dn'] + ' found') if c.response[0]['attributes']['objectGuid']: guid = c.response[0]['attributes']['objectGuid'] escaped_guid = escape_bytes(UUID(guid).bytes_le) print('Object GUID for %s is %s. Its escaped bytes value is %s' % (MY_USER, guid, escaped_guid)) print('Searching for guid ' + guid) if c.search(MY_BASE, '(objectGuid=%s)' % escaped_guid, attributes=['samAccountName', 'objectGUID']): print('Found user %s with object GUID %s' % (c.response[0]['attributes']['samAccountName'], c.response[0]['attributes']['objectGuid'])) else: print('ObjectGuid ' + guid + ' not found') else: print('objectGuid not found for ' + MY_USER) else: print(MY_USER + ' not found')
def trim_objectGUID(userId): userId = uuid.UUID("{{{0!s}}}".format(userId)).bytes_le userId = escape_bytes(userId) return userId
from .base import BaseDriver from ldap3 import Connection from ldap3.utils.conv import escape_bytes ldap_escape = lambda s: escape_bytes(s.encode()) class Driver(BaseDriver): connection = None def __init__(self, config, domains=[], **kwargs): self.config = config self.user_base = config["user base"] self.user_query = config["user query"] self.user_name_attribute = config["user name attribute"] self.user_mail_attribute = config["user mail attribute"] self.group_base = config["group base"] self.group_query = config["group query"] self.group_member_attribute = config["group member attribute"] self.domains = domains def get_connection(self, c=None): if c is None: return Connection(self.config["server"], self.config["binddn"], self.config["password"], True) else: return c