def getuserdata(login): server = LDAP_SERVER # getInfo=GET_ALL_INFO attributes = ['uid', 'distinguishedName', 'cn', 'mail', 'telephoneNumber', 'department', 'gidNumber', 'uidNumber'] # basedn = 'OU=Accounts,DC=nrel,DC=gov' basedn = 'DC=nrel,DC=gov' search_filter = '(uid=%s)' % login # define a synchronous connection with basic authentication conn = Connection(server, auto_bind=True, client_strategy=STRATEGY_ASYNC_THREADED, user=LDAP_USER, password=LDAP_PASS, authentication=AUTH_SIMPLE) ##client_strategy=STRATEGY_SYNC #conn.tls = tls() #conn.start_tls() result = conn.search(basedn, search_filter=search_filter, search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=attributes ) conn.get_response(result, timeout=10) data = conn.response # Check if a dict was returned, # meaning loginID is in LDAP and password works. if not data: return False # User has passed LDAP auth... # Finally, return the user's attribs. dn = data[0]['attributes'] return dn
class Test(unittest.TestCase): def setUp(self): server = Server(test_server, test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=False, pool_name='pool1') def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_modify(self): attribute1 = Attribute() vals1 = ValsAtLeast1() vals1[0] = AttributeValue('tost') attribute1['type'] = AttributeDescription('sn') attribute1['vals'] = vals1 attribute2 = Attribute() vals2 = ValsAtLeast1() vals2[0] = AttributeValue('tust') attribute2['type'] = AttributeDescription('givenName') attribute2['vals'] = vals2 attribute3 = Attribute() vals3 = ValsAtLeast1() vals3[0] = AttributeValue('inetOrgPerson') attribute3['type'] = AttributeDescription('objectClass') attribute3['vals'] = vals3 attributes = AttributeList() attributes[0] = attribute1 attributes[1] = attribute2 attributes[2] = attribute3 add_req = AddRequest() add_req['entry'] = LDAPDN(dn_for_test(test_base, 'test-modify')) add_req['attributes'] = attributes result = self.connection.post_send_single_response(self.connection.send('addRequest', add_req)) if not isinstance(result, bool): self.connection.get_response(result) vals_mod1 = Vals() vals_mod1[0] = 'test-modified' part_attr1 = PartialAttribute() part_attr1['type'] = AttributeDescription('sn') part_attr1['vals'] = vals_mod1 change1 = Change() change1['operation'] = Operation('replace') change1['modification'] = part_attr1 changes = Changes() changes[0] = change1 modify_req = ModifyRequest() modify_req['object'] = LDAPDN(dn_for_test(test_base, 'test-modify')) modify_req['changes'] = changes result = self.connection.post_send_single_response(self.connection.send('modifyRequest', modify_req)) if not isinstance(result, bool): self.connection.get_response(result) self.assertTrue(True)
class Test(unittest.TestCase): def setUp(self): server = Server(test_server, test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=False, pool_name='pool1') def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() def test_compare(self): attribute1 = Attribute() vals1 = ValsAtLeast1() vals1[0] = AttributeValue('tost') attribute1['type'] = AttributeDescription('sn') attribute1['vals'] = vals1 attribute2 = Attribute() vals2 = ValsAtLeast1() vals2[0] = AttributeValue('tust') attribute2['type'] = AttributeDescription('givenName') attribute2['vals'] = vals2 attribute3 = Attribute() vals3 = ValsAtLeast1() vals3[0] = AttributeValue('inetOrgPerson') attribute3['type'] = AttributeDescription('objectClass') attribute3['vals'] = vals3 attributes = AttributeList() attributes[0] = attribute1 attributes[1] = attribute2 attributes[2] = attribute3 add_req = AddRequest() add_req['entry'] = LDAPDN(dn_for_test(test_base, 'test-compare')) add_req['attributes'] = attributes result = self.connection.post_send_single_response(self.connection.send('addRequest', add_req)) if not isinstance(result, bool): self.connection.get_response(result) ava = AttributeValueAssertion() ava['attributeDesc'] = AttributeDescription('givenName') ava['assertionValue'] = AssertionValue('tust') compare_req = CompareRequest() compare_req['entry'] = LDAPDN(dn_for_test(test_base, 'test-compare')) compare_req['ava'] = ava result = self.connection.post_send_single_response(self.connection.send('compareRequest', compare_req)) if not isinstance(result, bool): self.connection.get_response(result) self.assertTrue(True)
def test_raise_exceptions(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info) connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=test_check_names, raise_exceptions=True) ok = False try: result = connection.search('xxx=xxx', '(cn=*)') if not isinstance(result, bool): connection.get_response(result) except LDAPNoSuchObjectResult: ok = True self.assertTrue(ok)
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1') def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_get_replica_list_extension(self): result = self.connection.extended('2.16.840.1.113719.1.27.100.19', 'cn=server') if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result print(result['description']) self.assertTrue(result['description'] in ['success', 'noSuchObject']) def test_who_am_i_extension(self): result = self.connection.extended('1.3.6.1.4.1.4203.1.11.3') if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'protocolError']) def test_get_bind_dn_extension(self): result = self.connection.extended('2.16.840.1.113719.1.27.100.31') if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success']) def test_start_tls_extension(self): self.connection.server.tls = Tls() result = self.connection.extended('1.3.6.1.4.1.1466.20037') if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success'])
class Test(unittest.TestCase): def setUp(self): server = Server(test_server, test_port) self.connection = Connection(server, auto_bind=True, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, pool_name='pool1') def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() def test_bind(self): bind_req = BindRequest() bind_req['version'] = Version(3) bind_req['name'] = LDAPDN(test_user) bind_req['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple(test_password)) result = self.connection.post_send_single_response(self.connection.send('bindRequest', bind_req)) if not isinstance(result, bool): self.connection.get_response(result) self.assertTrue(True)
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1') result = self.connection.add(dn_for_test(test_base, 'test-add-for-delete'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-add'}) if not isinstance(result, bool): self.connection.get_response(result) def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_delete(self): result = self.connection.delete(dn_for_test(test_base, 'test-add-for-delete')) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'noSuchObject'])
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=test_check_names) result = self.connection.delete(dn_for_test(test_base, 'test-add-operation')) if not isinstance(result, bool): self.connection.get_response(result) def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) @pytest.mark.skipif(True, reason="needs rework") def test_add(self): result = self.connection.add(dn_for_test(test_base, 'test-add-operation'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-add', test_name_attr: 'test-add-operation'}) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'entryAlreadyExists'])
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1') result = self.connection.add(dn_for_test(test_base, 'test-ldif-1'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-ldif-1', test_name_attr: 'test-ldif-1'}) if not isinstance(result, bool): self.connection.get_response(result) result = self.connection.add(dn_for_test(test_base, 'test-ldif-2'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-ldif-2', test_name_attr: 'test-ldif-2'}) if not isinstance(result, bool): self.connection.get_response(result) def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_single_search_result_to_ldif(self): result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=test-ldif-1)', attributes=[test_name_attr, 'givenName', 'jpegPhoto', 'sn', 'cn', 'objectClass']) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result l = self.connection.response_to_ldif(response) self.assertTrue('version: 1' in l) self.assertTrue('dn: cn=test-ldif-1,o=test' in l) self.assertTrue('objectClass: inetOrgPerson' in l) self.assertTrue('objectClass: Top' in l) self.assertTrue('cn: test-ldif-1' in l) self.assertTrue('sn: test-ldif-1' in l) self.assertTrue('total number of entries: 1' in l) def test_multiple_search_result_to_ldif(self): result = self.connection.search(search_base=test_base, search_filter='(sn=test-ldif*)', attributes=[test_name_attr, 'givenName', 'sn', 'objectClass']) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result l = self.connection.response_to_ldif(response) self.assertTrue('version: 1' in l) self.assertTrue('dn: cn=test-ldif-1,o=test' in l) self.assertTrue('objectClass: inetOrgPerson' in l) self.assertTrue('objectClass: Top' in l) self.assertTrue('cn: test-ldif-1' in l) self.assertTrue('sn: test-ldif-1' in l) self.assertTrue('dn: cn=test-ldif-2,o=test' in l) self.assertTrue('cn: test-ldif-2' in l) self.assertTrue('sn: test-ldif-2' in l) self.assertTrue('total number of entries: 2' in l)
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1') def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_search_with_controls(self): controls = list() controls.append(('2.16.840.1.113719.1.27.103.7', True, 'givenName')) result = self.connection.search(test_base, '(objectClass=*)', attributes=['sn, givenName'], size_limit=0, controls=controls) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'operationsError'])
class Test(unittest.TestCase): def setUp(self): self.connection = Connection(server=None, client_strategy=LDIF) self.connection.open() def tearDown(self): self.connection.unbind() self.assertFalse(self.connection.bound) def test_add_request_to_ldif(self): controls = list() controls.append(('2.16.840.1.113719.1.27.103.7', True, 'givenName')) controls.append(('2.16.840.1.113719.1.27.103.7', False, 'sn')) if str != bytes: # python3 controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray('\u00e0\u00e0', encoding='UTF-8'))) else: controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray(unicode('\xe0\xe0', encoding='latin1'), encoding='UTF-8'))) # for python2 compatability controls.append(('2.16.840.1.113719.1.27.103.7', False, 'trailingspace ')) self.connection.add(generate_dn(test_base, testcase_id, 'ldif-change-1'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'ldif-change-1', test_name_attr: 'ldif-change-1'}, controls=controls) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-1,' + test_base in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 true: givenName' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false: sn' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: w6DDoA==' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: dHJhaWxpbmdzcGFjZSA=' in response) self.assertTrue('changetype: add' in response) self.assertTrue('objectClass: iNetOrgPerson' in response) self.assertTrue('sn: ldif-change-1' in response) self.assertTrue(test_name_attr + ': ldif-change-1' in response) def test_delete_request_to_ldif(self): self.connection.strategy.order = dict(delRequest=['dn:', 'changetype', 'vers']) self.connection.delete(generate_dn(test_base, testcase_id, 'ldif-change-2')) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-2,' + test_base in response) self.assertTrue('changetype: delete' in response) def test_modify_dn_request_to_ldif(self): result = self.connection.modify_dn(generate_dn(test_base, testcase_id, 'ldif-change-3'), test_name_attr + '=' + testcase_id + 'ldif-change-4,' + test_base) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-3,' + test_base in response) self.assertTrue('changetype: moddn' in response) self.assertTrue('newrdn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-4,' + test_base in response) self.assertTrue('deleteoldrdn: 1' in response) def test_move_dn_request_to_ldif(self): result = self.connection.modify_dn(generate_dn(test_base, testcase_id, 'ldif-change-5'), test_name_attr + '=' + testcase_id + 'ldif-change-5', delete_old_dn=False, new_superior=test_moved) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-5,' + test_base in response) self.assertTrue('changetype: modrdn' in response) self.assertTrue('newrdn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-5' in response) self.assertTrue('deleteoldrdn: 0' in response) self.assertTrue('newsuperior: ' + test_moved in response) def test_modify_add_to_ldif(self): result = self.connection.modify(generate_dn(test_base, testcase_id, 'ldif-change-6'), {'givenName': (MODIFY_ADD, ['givenname-6-modified'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-6,' + test_base in response) self.assertTrue('changetype: modify' in response) self.assertTrue('add: givenName' in response) self.assertTrue('givenName: givenname-6-modified' in response) self.assertEqual('-', response[-1]) def test_modify_replace_to_ldif(self): result = self.connection.modify(generate_dn(test_base, testcase_id, 'ldif-change-7'), {'givenName': (MODIFY_REPLACE, ['givenname-7-replaced'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-7,' + test_base in response) self.assertTrue('changetype: modify' in response) self.assertTrue('replace: givenName' in response) self.assertTrue('givenName: givenname-7-replaced' in response) self.assertEqual('-', response[-1]) def test_modify_delete_to_ldif(self): result = self.connection.modify(generate_dn(test_base, testcase_id, 'ldif-change-8'), {'givenName': (MODIFY_DELETE, ['givenname-8-deleted'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-8,' + test_base in response) self.assertTrue('changetype: modify' in response) self.assertTrue('delete: givenName' in response) self.assertTrue('givenName: givenname-8-deleted' in response) self.assertEqual('-', response[-1]) def test_multiple_modify_to_ldif(self): # from rfc 2849 example result = self.connection.modify('cn=Paula Jensen, ou=Product Development, dc=airius, dc=com', {'postaladdress': (MODIFY_ADD, ['123 Anystreet $ Sunnyvale, CA $ 94086']), 'description': (MODIFY_DELETE, []), 'telephonenumber': (MODIFY_REPLACE, ['+1 408 555 1234', '+1 408 555 5678']), 'facsimiletelephonenumber': (MODIFY_DELETE, ['+1 408 555 9876'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com' in response) self.assertTrue('changetype: modify' in response) self.assertTrue('delete: facsimiletelephonenumber' in response) self.assertTrue('facsimiletelephonenumber: +1 408 555 9876' in response) self.assertTrue('replace: telephonenumber' in response) self.assertTrue('telephonenumber: +1 408 555 1234' in response) self.assertTrue('telephonenumber: +1 408 555 5678' in response) self.assertTrue('add: postaladdress' in response) self.assertTrue('postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086' in response) self.assertTrue('delete: description' in response) self.assertEqual('-', response[-1])
class Test(unittest.TestCase): def setUp(self): self.connection = Connection(server=None, client_strategy=LDIF) self.connection.open() def tearDown(self): self.connection.unbind() self.assertFalse(self.connection.bound) def test_add_request_to_ldif(self): controls = list() controls.append(('2.16.840.1.113719.1.27.103.7', True, 'givenName')) controls.append(('2.16.840.1.113719.1.27.103.7', False, 'sn')) if str != bytes: # python3 controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray('\u00e0\u00e0', encoding='UTF-8'))) else: controls.append( ('2.16.840.1.113719.1.27.103.7', False, bytearray(unicode('\xe0\xe0', encoding='latin1'), encoding='UTF-8'))) # for python2 compatability controls.append( ('2.16.840.1.113719.1.27.103.7', False, 'trailingspace ')) self.connection.add(generate_dn(test_base, testcase_id, 'ldif-change-1'), 'inetOrgPerson', { 'objectClass': 'inetOrgPerson', 'sn': 'ldif-change-1', test_name_attr: 'ldif-change-1' }, controls=controls) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-1,' + test_base in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 true: givenName' in response) self.assertTrue( 'control: 2.16.840.1.113719.1.27.103.7 false: sn' in response) self.assertTrue( 'control: 2.16.840.1.113719.1.27.103.7 false:: w6DDoA==' in response) self.assertTrue( 'control: 2.16.840.1.113719.1.27.103.7 false:: dHJhaWxpbmdzcGFjZSA=' in response) self.assertTrue('changetype: add' in response) self.assertTrue('objectClass: inetOrgPerson' in response) self.assertTrue('sn: ldif-change-1' in response) self.assertTrue(test_name_attr + ': ldif-change-1' in response) def test_delete_request_to_ldif(self): self.connection.strategy.order = dict( delRequest=['dn:', 'changetype', 'vers']) self.connection.delete( generate_dn(test_base, testcase_id, 'ldif-change-2')) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-2,' + test_base in response) self.assertTrue('changetype: delete' in response) def test_modify_dn_request_to_ldif(self): result = self.connection.modify_dn( generate_dn(test_base, testcase_id, 'ldif-change-3'), test_name_attr + '=' + testcase_id + 'ldif-change-4,' + test_base) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-3,' + test_base in response) self.assertTrue('changetype: moddn' in response) self.assertTrue('newrdn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-4,' + test_base in response) self.assertTrue('deleteoldrdn: 1' in response) def test_move_dn_request_to_ldif(self): result = self.connection.modify_dn( generate_dn(test_base, testcase_id, 'ldif-change-5'), test_name_attr + '=' + testcase_id + 'ldif-change-5', delete_old_dn=False, new_superior=test_moved) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-5,' + test_base in response) self.assertTrue('changetype: modrdn' in response) self.assertTrue('newrdn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-5' in response) self.assertTrue('deleteoldrdn: 0' in response) self.assertTrue('newsuperior: ' + test_moved in response) def test_modify_add_to_ldif(self): result = self.connection.modify( generate_dn(test_base, testcase_id, 'ldif-change-6'), {'givenName': (MODIFY_ADD, ['givenname-6-modified'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-6,' + test_base in response) self.assertTrue('changetype: modify' in response) self.assertTrue('add: givenName' in response) self.assertTrue('givenName: givenname-6-modified' in response) self.assertEqual('-', response[-1]) def test_modify_replace_to_ldif(self): result = self.connection.modify( generate_dn(test_base, testcase_id, 'ldif-change-7'), {'givenName': (MODIFY_REPLACE, ['givenname-7-replaced'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-7,' + test_base in response) self.assertTrue('changetype: modify' in response) self.assertTrue('replace: givenName' in response) self.assertTrue('givenName: givenname-7-replaced' in response) self.assertEqual('-', response[-1]) def test_modify_delete_to_ldif(self): result = self.connection.modify( generate_dn(test_base, testcase_id, 'ldif-change-8'), {'givenName': (MODIFY_DELETE, ['givenname-8-deleted'])}) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-8,' + test_base in response) self.assertTrue('changetype: modify' in response) self.assertTrue('delete: givenName' in response) self.assertTrue('givenName: givenname-8-deleted' in response) self.assertEqual('-', response[-1]) def test_multiple_modify_to_ldif(self): # from rfc 2849 example result = self.connection.modify( 'cn=Paula Jensen,ou=Product Development,dc=airius,dc=com', { 'postaladdress': (MODIFY_ADD, ['123 Anystreet $ Sunnyvale, CA $ 94086']), 'description': (MODIFY_DELETE, []), 'telephonenumber': (MODIFY_REPLACE, ['+1 408 555 1234', '+1 408 555 5678']), 'facsimiletelephonenumber': (MODIFY_DELETE, ['+1 408 555 9876']) }) if isinstance(result, int): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue( 'dn: cn=Paula Jensen,ou=Product Development,dc=airius,dc=com' in response) self.assertTrue('changetype: modify' in response) self.assertTrue('delete: facsimiletelephonenumber' in response) self.assertTrue( 'facsimiletelephonenumber: +1 408 555 9876' in response) self.assertTrue('replace: telephonenumber' in response) self.assertTrue('telephonenumber: +1 408 555 1234' in response) self.assertTrue('telephonenumber: +1 408 555 5678' in response) self.assertTrue('add: postaladdress' in response) self.assertTrue( 'postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086' in response) self.assertTrue('delete: description' in response) self.assertEqual('-', response[-1])
def get_connection(bind=None, use_ssl=None, check_names=None, lazy_connection=None, authentication=None, sasl_mechanism=None, sasl_credentials=None, ntlm_credentials=(None, None), get_info=None, usage=None, internal_decoder=None, simple_credentials=(None, None), receive_timeout=None, auto_escape=None, auto_encode=None): if bind is None: bind = True if check_names is None: check_names = test_check_names if lazy_connection is None: lazy_connection = test_lazy_connection if authentication is None: authentication = test_authentication if get_info is None: get_info = test_get_info if usage is None: usage = test_usage if internal_decoder is None: internal_decoder = test_internal_decoder if receive_timeout is None: receive_timeout = test_receive_timeout if auto_escape is None: auto_escape = test_auto_escape if auto_encode is None: auto_encode = test_auto_encode if test_server_type == 'AD' and use_ssl is None: use_ssl = True # Active directory forbids Add operations in cleartext if test_strategy not in [MOCK_SYNC, MOCK_ASYNC]: # define real server if isinstance(test_server, (list, tuple)): server = ServerPool(pool_strategy=test_pooling_strategy, active=test_pooling_active, exhaust=test_pooling_exhaust) for host in test_server: server.add( Server(host=host, use_ssl=use_ssl, port=test_port_ssl if use_ssl else test_port, allowed_referral_hosts=('*', True), get_info=get_info, mode=test_server_mode)) else: server = Server(host=test_server, use_ssl=use_ssl, port=test_port_ssl if use_ssl else test_port, allowed_referral_hosts=('*', True), get_info=get_info, mode=test_server_mode) else: if test_server_type == 'EDIR': schema = SchemaInfo.from_json(edir_9_1_4_schema) info = DsaInfo.from_json(edir_9_1_4_dsa_info, schema) server = Server.from_definition('MockSyncServer', info, schema) elif test_server_type == 'AD': schema = SchemaInfo.from_json(ad_2012_r2_schema) info = DsaInfo.from_json(ad_2012_r2_dsa_info, schema) server = Server.from_definition('MockSyncServer', info, schema) elif test_server_type == 'SLAPD': schema = SchemaInfo.from_json(slapd_2_4_schema) info = DsaInfo.from_json(slapd_2_4_dsa_info, schema) server = Server.from_definition('MockSyncServer', info, schema) if authentication == SASL: connection = Connection(server, auto_bind=bind, version=3, client_strategy=test_strategy, authentication=SASL, sasl_mechanism=sasl_mechanism, sasl_credentials=sasl_credentials, lazy=lazy_connection, pool_name='pool1', pool_size=test_pool_size, check_names=check_names, collect_usage=usage, fast_decoder=internal_decoder, receive_timeout=receive_timeout, auto_escape=auto_escape, auto_encode=auto_encode) elif authentication == NTLM: connection = Connection(server, auto_bind=bind, version=3, client_strategy=test_strategy, user=ntlm_credentials[0], password=ntlm_credentials[1], authentication=NTLM, lazy=lazy_connection, pool_name='pool1', pool_size=test_pool_size, check_names=check_names, collect_usage=usage, fast_decoder=internal_decoder, receive_timeout=receive_timeout, auto_escape=auto_escape, auto_encode=auto_encode) elif authentication == ANONYMOUS: connection = Connection(server, auto_bind=bind, version=3, client_strategy=test_strategy, user=None, password=None, authentication=ANONYMOUS, lazy=lazy_connection, pool_name='pool1', pool_size=test_pool_size, check_names=check_names, collect_usage=usage, fast_decoder=internal_decoder, receive_timeout=receive_timeout, auto_escape=auto_escape, auto_encode=auto_encode) else: connection = Connection(server, auto_bind=bind, version=3, client_strategy=test_strategy, user=simple_credentials[0] or test_user, password=simple_credentials[1] or test_password, authentication=authentication, lazy=lazy_connection, pool_name='pool1', pool_size=test_pool_size, check_names=check_names, collect_usage=usage, fast_decoder=internal_decoder, receive_timeout=receive_timeout, auto_escape=auto_escape, auto_encode=auto_encode) if test_strategy in [MOCK_SYNC, MOCK_ASYNC]: # create authentication identities for testing mock strategies connection.strategy.add_entry(test_user, { 'objectClass': 'inetOrgPerson', 'userPassword': test_password }) connection.strategy.add_entry( test_secondary_user, { 'objectClass': 'inetOrgPerson', 'userPassword': test_secondary_password }) connection.strategy.add_entry(test_sasl_user_dn, { 'objectClass': 'inetOrgPerson', 'userPassword': test_sasl_password }) connection.strategy.add_entry( test_sasl_secondary_user_dn, { 'objectClass': 'inetOrgPerson', 'userPassword': test_sasl_secondary_password }) # connection.strategy.add_entry(test_ntlm_user, {'objectClass': 'inetOrgPerson', 'userPassword': test_ntlm_password}) if bind: connection.bind() if 'TRAVIS,' in location and test_server_type == 'SLAPD' and not connection.closed: # try to create the contexts for fixtures result1 = connection.add(test_base, 'organizationalUnit') result2 = connection.add(test_moved, 'organizationalUnit') if not connection.strategy.sync: connection.get_response(result1) connection.get_response(result2) return connection
class Test(unittest.TestCase): def setUp(self): # server = Server(host = test_server, port = test_port, allowed_referral_hosts = ('*', True)) self.connection = Connection(server=None, client_strategy=STRATEGY_LDIF_PRODUCER) self.connection.open() def tearDown(self): self.connection.unbind() self.assertFalse(self.connection.bound) def test_add_request_to_ldif(self): controls = list() controls.append(('2.16.840.1.113719.1.27.103.7', True, 'givenName')) controls.append(('2.16.840.1.113719.1.27.103.7', False, 'sn')) if str != bytes: # python3 controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray('\u00e0\u00e0', encoding='UTF-8'))) else: controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray(unicode('\xe0\xe0', encoding='latin1'), encoding='UTF-8'))) # for python2 compatability controls.append(('2.16.840.1.113719.1.27.103.7', False, 'trailingspace ')) self.connection.add(dn_for_test(test_base, 'test-add-operation'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-add', test_name_attr: 'test-add-operation'}, controls=controls) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-add-operation,o=test' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 true: givenName' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false: sn' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: w6DDoA==' in response) self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: dHJhaWxpbmdzcGFjZSA=' in response) self.assertTrue('changetype: add' in response) self.assertTrue('objectClass: inetorgperson' in response) self.assertTrue('sn: test-add' in response) self.assertTrue('cn: test-add-operation' in response) def test_delete_request_to_ldif(self): self.connection.strategy.order = dict(delRequest=['dn:', 'changetype', 'vers']) self.connection.delete(dn_for_test(test_base, 'test-del-operation')) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-del-operation,o=test' in response) self.assertTrue('changetype: delete' in response) def test_modify_dn_request_to_ldif(self): result = self.connection.modify_dn(dn_for_test(test_base, 'test-modify-dn-operation'), test_name_attr + '=test-modified-dn-operation') if not isinstance(result, bool): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-modify-dn-operation,o=test' in response) self.assertTrue('changetype: moddn' in response) self.assertTrue('newrdn: cn=test-modified-dn-operation' in response) self.assertTrue('deleteoldrdn: 1' in response) def test_move_dn_request_to_ldif(self): result = self.connection.modify_dn(dn_for_test(test_base, 'test-move-dn-operation'), test_name_attr + '=test-move-dn-operation', delete_old_dn=False, new_superior=test_moved) if not isinstance(result, bool): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-move-dn-operation,o=test' in response) self.assertTrue('changetype: modrdn' in response) self.assertTrue('newrdn: cn=test-move-dn-operation' in response) self.assertTrue('deleteoldrdn: 0' in response) self.assertTrue('newsuperior: ou=moved,o=test' in response) def test_modify_add_to_ldif(self): result = self.connection.modify(dn_for_test(test_base, 'test-add-for-modify'), {'givenName': (MODIFY_ADD, ['test-modified-added'])}) if not isinstance(result, bool): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-add-for-modify,o=test' in response) self.assertTrue('changetype: modify' in response) self.assertTrue('add: givenName' in response) self.assertTrue('givenName: test-modified-added' in response) self.assertEqual('-', response[-1]) def test_modify_replace_to_ldif(self): result = self.connection.modify(dn_for_test(test_base, 'test-add-for-modify'), {'givenName': (MODIFY_REPLACE, ['test-modified-replace'])}) if not isinstance(result, bool): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-add-for-modify,o=test' in response) self.assertTrue('changetype: modify' in response) self.assertTrue('replace: givenName' in response) self.assertTrue('givenName: test-modified-replace' in response) self.assertEqual('-', response[-1]) def test_modify_delete_to_ldif(self): result = self.connection.modify(dn_for_test(test_base, 'test-add-for-modify'), {'givenName': (MODIFY_DELETE, ['test-modified-added2'])}) if not isinstance(result, bool): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=test-add-for-modify,o=test' in response) self.assertTrue('changetype: modify' in response) self.assertTrue('delete: givenName' in response) self.assertTrue('givenName: test-modified-added2' in response) self.assertEqual('-', response[-1]) def test_multiple_modify_to_ldif(self): # from rfc 2849 example result = self.connection.modify('cn=Paula Jensen, ou=Product Development, dc=airius, dc=com', {'postaladdress': (MODIFY_ADD, ['123 Anystreet $ Sunnyvale, CA $ 94086']), 'description': (MODIFY_DELETE, []), 'telephonenumber': (MODIFY_REPLACE, ['+1 408 555 1234', '+1 408 555 5678']), 'facsimiletelephonenumber': (MODIFY_DELETE, ['+1 408 555 9876'])}) if not isinstance(result, bool): self.connection.get_response(result) response = self.connection.response self.assertTrue('version: 1' in response) self.assertTrue('dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com' in response) self.assertTrue('changetype: modify' in response) self.assertTrue('delete: facsimiletelephonenumber' in response) self.assertTrue('facsimiletelephonenumber: +1 408 555 9876' in response) self.assertTrue('replace: telephonenumber' in response) self.assertTrue('telephonenumber: +1 408 555 1234' in response) self.assertTrue('telephonenumber: +1 408 555 5678' in response) self.assertTrue('add: postaladdress' in response) self.assertTrue('postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086' in response) self.assertTrue('delete: description' in response) self.assertEqual('-', response[-1])
class LDAPUserManager(object): def __init__( self, ldap_server, user_filter, base_dn=None, root_dn=None, passwd_dn=None, user_profile=[], read_only=True, cache_users=None, cache_groups=None): self.ldap_server = ldap_server self.root_dn = root_dn self.passwd_dn = passwd_dn self.base_dn = base_dn self.user_filter = user_filter self.user_profile = user_profile self.read_only = read_only self.cache_users = cache_users self.cache_groups = cache_groups self.ttl_users = 3660 self.bind() def scopes_filter(self): f = 'ou=scopes,' + self.base_dn return f def scope_filter(self, scope): f = 'ou={scope},' + self.scopes_filter() return f.format(scope=scope) def groups_filter(self, scope): return 'ou=groups,' + self.scope_filter(scope=scope) def group_filter(self, scope, group): f = 'cn={group},' + self.groups_filter(scope=scope) return f.format(group=group) def roles_filter(self, scope): return 'ou=roles,' + self.scope_filter(scope=scope) def role_filter(self, scope, role): f = 'cn={role},' + self.roles_filter(scope) return f.format(role=role) def users_filter(self): f = 'ou=users,' + self.base_dn return f def userdn2id(self, user_dn): """ :param user_dn: can be a user or a group dn :type user_dn: str """ parse_dn = None if user_dn.startswith('mail='): parse_dn = 'mail=' elif user_dn.startswith('cn='): parse_dn = 'cn=' if parse_dn: return user_dn[len(parse_dn):user_dn.find(',')] def bind(self): if self.root_dn is None: raise Exception('No LDAP Admin Configuration') authentication_method = SIMPLE bind_type = ASYNC self.ldap_conn_mng = Connection( self.ldap_server, authentication=authentication_method, client_strategy=bind_type, user=self.root_dn, password=self.passwd_dn, read_only=self.read_only) self.ldap_conn_mng.bind() def bind_root_readonly(self): """ A root connection to LDAP server only read_only """ if self.root_dn is None: raise Exception('No LDAP Admin Configuration') authentication_method = SIMPLE bind_type = ASYNC ldap_conn_mng = Connection( self.ldap_server, authentication=authentication_method, client_strategy=bind_type, user=self.root_dn, password=self.passwd_dn, read_only=True) ldap_conn_mng.bind() return ldap_conn_mng def unbind(self): self.ldap_conn_mng.unbind() def checkUserName(self, username): if ',' in username: raise TypeError('No , in username') def parse_async_add(self, return_code): """ Parser the response for an LDAP async ADD """ result = 'Not done' if return_code: result = self.ldap_conn_mng.get_response(return_code) result = result[1].get('description', 'Error no description') return result async def addScope(self, scope): """ !!!Admin add: must be protected when calling """ # Needs admin if self.read_only: raise Exception('LDAP in Read only mode') self.bind() scope_dn = self.scope_filter(scope=scope) done = self.ldap_conn_mng.add(scope_dn, 'organizationalUnit') result = self.parse_async_add(done) if result == 'success': #add subelements for scope roles_dn = self.roles_filter(scope=scope) done = self.ldap_conn_mng.add(roles_dn, 'organizationalUnit') if self.parse_async_add(done) != 'success': result = 'Failed creating roles' groups_dn = self.groups_filter(scope=scope) done = self.ldap_conn_mng.add(groups_dn, 'organizationalUnit') if self.parse_async_add(done) != 'success': result = 'Failed creating groups' self.unbind() return result def addUser(self, username, password): """ !!!Admin add: must be protected when calling """ # Needs admin if self.read_only: raise Exception('LDAP in Read only mode') self.bind() self.checkUserName(username) user_dn = self.user_filter.format(username=username) if '@' in username: sn = username.split('@')[0] else: sn = username done = self.ldap_conn_mng.add( user_dn, self.user_profile, { 'cn': username, 'sn': sn, 'mail': username, 'userPassword': password, }) result = self.parse_async_add(done) self.unbind() return result async def addGroup(self, scope, group): """ !!!Admin add: must be protected when calling """ # Needs admin if self.read_only: raise Exception('LDAP in Read only mode') self.bind() self.checkUserName(group) group_dn = self.group_filter(scope=scope, group=group) done = self.ldap_conn_mng.add( group_dn, 'groupOfUniqueNames', { 'cn': group, 'uniqueMember': group_dn # group itself as an empty members list }) result = self.parse_async_add(done) self.unbind() return result async def setPassword(self, username, password): """ !!!Admin add: must be protected when calling """ # Needs admin if self.read_only: raise Exception('LDAP in Read only mode') self.bind() user_dn = self.user_filter.format(username=username) hashed_password = hashed(HASHED_SHA512, password) done = self.ldap_conn_mng.modify( user_dn, {'userPassword': [(MODIFY_REPLACE, [hashed_password])]} ) result = self.parse_async_add(done) if result == 'success': return True else: return False async def addScopeRole(self, scope, user_dn, role): """ !!!Admin add: must be protected when calling `user_dn` can be a user or a group dn. """ # Needs admin if self.read_only: raise Exception('LDAP in Read only mode') self.bind() role_dn = self.role_filter(scope=scope, role=role.lower()) #Create role for first time done = self.ldap_conn_mng.add( role_dn, 'groupOfUniqueNames', {'cn': role, 'uniqueMember': user_dn} ) result = self.parse_async_add(done) if result == 'entryAlreadyExists': #Extend role with new user done = self.ldap_conn_mng.modify( role_dn, {'uniqueMember': [(MODIFY_ADD, [user_dn])]} ) result = self.parse_async_add(done) self.unbind() return result async def addScopeRoleUser(self, scope, username, role): user_dn = self.user_filter.format(username=username) return await self.addScopeRole(scope, user_dn, role) async def addScopeRoleGroup(self, scope, groupname, role): group_dn = self.group_filter(scope, groupname) return await self.addScopeRole(scope, group_dn, role) async def delScopeRole(self, scope, username, role): """ !!!Admin del: must be protected when calling """ # Needs admin if self.read_only: raise Exception('LDAP in Read only mode') self.bind() role_dn = self.role_filter(scope=scope, role=role.lower()) user_dn = self.user_filter.format(username=username) #Find role for first time done = self.ldap_conn_mng.modify( role_dn, {'uniqueMember': [(MODIFY_DELETE, [user_dn])]} ) result = self.parse_async_add(done) if result == 'objectClassViolation': # member was the last remaining done = self.ldap_conn_mng.delete(role_dn) result = self.parse_async_add(done) self.unbind() return result async def searchUser(self, scope, criteria, exact_match, attrs, page=None, num_x_page=0): """ !!!Admin search: must be protected when calling """ total = 0 result = [] paged_size = num_x_page paged_cookie = page if exact_match is False and any(criteria.values()): for k in criteria.keys(): criteria[k] = "*" + criteria[k] + "*" for objclass in self.user_profile: criteria['objectClass'] = objclass filter_ldap = "" for j, v in criteria.items(): filter_ldap += "(%s=%s)" % (j, v) filter_ldap = "(&%s)" % filter_ldap self.ldap_conn_mng.bind() done = self.ldap_conn_mng.search( self.base_dn, filter_ldap, search_scope=SUBTREE, dereference_aliases=DEREF_ALWAYS, attributes=USER_ATTRIBUTES, size_limit=0, time_limit=0, types_only=False, get_operational_attributes=False, controls=None, paged_size=paged_size, paged_criticality=False, paged_cookie=paged_cookie) if done: result = self.ldap_conn_mng.get_response(done)[0] total = len(result) self.ldap_conn_mng.unbind() return [dict(r['attributes']) for r in result], total async def getUser(self, dn, ldap_conn): # We should be logged in with the user with (await self.cache_users) as redis: user = await redis.get(dn) if user and user != b'{}': return ujson.loads(user) r = ldap_conn.search( dn, '(objectClass=*)', search_scope=BASE, attributes=USER_ATTRIBUTES) if r: res = ldap_conn.response[0] with (await self.cache_users) as redis: redis.set(res['dn'], ujson.dumps(dict(res['attributes']))) redis.expire(res['dn'], self.ttl_users) return res['attributes'] async def loginUser(self, username, password): user_dn = self.user_filter.format(username=username) bind_type = SYNC authentication_method = SIMPLE ldap_conn = Connection( self.ldap_server, authentication=authentication_method, client_strategy=bind_type, user=user_dn, password=password, read_only=True) try: result = ldap_conn.bind() if result: user = await self.getUser(user_dn, ldap_conn) ldap_conn.unbind() return user else: return None except LDAPException: return None async def getUserName(self, username): dn = self.user_filter.format(username=username) with (await self.cache_users) as redis: user = await redis.get(dn) if user and user != b'{}': return ujson.loads(user) ldap_conn = self.bind_root_readonly() r = ldap_conn.search( dn, '(objectClass=*)', search_scope=BASE, attributes=USER_ATTRIBUTES) if r: names = ldap_conn.get_response(r)[0] res = [res['attributes']['cn'][0] for res in names] else: res = [] ldap_conn.unbind() return ' '.join(res) async def get_user_groups(self, ldap_conn, scope, user_dn): """ Return all groups cn that `user_dn` has in `scope` :param user_dn: can be a user or a group dn :type user_dn: str """ groups_dn = self.groups_filter(scope=scope) search_filter = '(uniqueMember={0})'.format(user_dn) r = ldap_conn.search( groups_dn, search_filter, search_scope=SUBTREE, attributes=['cn'] ) if r: groups = ldap_conn.get_response(r)[0] groups = filter(lambda x: x['dn'] != user_dn, groups) # filter self return [res['attributes']['cn'][0] for res in groups] async def get_user_roles(self, ldap_conn, scope, user_dn, groups=None): """ Return all roles cn that `user_dn` has in `scope`. Return all roles cn that each of `groups` has in `scope`. :param user_dn: can be a user or a group dn :type user_dn: str :param groups: (Optionally) :type groups: list """ roles_dn = self.roles_filter(scope=scope) search_filter = '(uniqueMember={0})'.format(user_dn) if groups is not None: search_filter = '(|' + search_filter for group_cn in groups: group_dn = self.group_filter(scope=scope, group=group_cn) search_filter += '(uniqueMember={0})'.format(group_dn) search_filter += ')' r = ldap_conn.search( roles_dn, search_filter, search_scope=SUBTREE, attributes=['cn'] ) if r: roles = ldap_conn.get_response(r)[0] return [res['attributes']['cn'][0] for res in roles] async def get_info_user_or_group(self, user_dn, scope): """ !!!Admin search: must be protected when calling :returns: { 'groups': { 'group1': 1, }, 'roles': { 'plone.Manager': 1, } } """ ldap_conn = self.bind_root_readonly() groups = await self.get_user_groups(ldap_conn, scope, user_dn) roles = await self.get_user_roles( ldap_conn, scope, user_dn, groups=groups, ) ldap_conn.unbind() return { 'roles': {e: 1 for e in roles}, 'groups': {e: 1 for e in groups}, } async def getUserInfo(self, username, scope): """ !!!Admin search: must be protected when calling :returns: { 'groups': { 'group1': 1, }, 'roles': { 'plone.Manager': 1, } 'name': 'Name' } """ user_dn = self.user_filter.format(username=username) info = await self.get_info_user_or_group(user_dn, scope) info['name'] = username return info async def getGroupInfo(self, scope, group=None): """ !!!Admin search: must be protected when calling :rtype: dict or list of dict or None :returns: { 'members': [ member1, ], 'name': 'Name' } or list of groups if group is None or None if group is not found """ ldap_conn = self.bind_root_readonly() groups_dn = self.groups_filter(scope=scope) if group is None: search_filter = '(objectClass=groupOfUniqueNames)' else: search_filter = '(cn={0})'.format(group) r = ldap_conn.search( groups_dn, search_filter, search_scope=SUBTREE, attributes=['cn', 'uniqueMember'] ) if not r: raise Exception('LDAP Group search bad formed') groups = ldap_conn.get_response(r)[0] ldap_conn.unbind() async def ldap2json(entry): group_dn = entry['dn'] group_name = entry['attributes']['cn'][0] members_ldap = entry['attributes']['uniqueMember'] members_ldap = filter(lambda x: x != group_dn, members_ldap) # filter self info = await self.get_info_user_or_group(group_dn, scope) info.update({ 'name': group_name, 'members': list(map(self.userdn2id, members_ldap)), }) return info groups = await asyncio.gather(*map(ldap2json, groups)) if group is None: return groups try: return groups[0] except IndexError: return None async def get_all_scopes(self, ldap_conn): """ """ r = ldap_conn.search( self.scopes_filter(), "(objectClass=organizationalUnit)", search_scope=LEVEL, attributes=['ou'] ) if r: scopes = ldap_conn.get_response(r)[0] return [scope['attributes']['ou'][0] for scope in scopes] async def getUserScopes(self, username): """ Aquesta crida retorna tots els scopes als quals pertany un usuari Nota: es pot millorar. Recorre dos cops tots els scopes. Un cop per obtenir-los tots i un altre per filtrar segons si l'usuari pertany o no """ ldap_conn = self.bind_root_readonly() all_scopes = await self.get_all_scopes(ldap_conn) if plone.oauth.is_superuser(username): scopes = all_scopes else: user_dn = self.user_filter.format(username=username) scopes = [] for scope in all_scopes: roles = await self.get_user_roles(ldap_conn, scope, user_dn) if roles: scopes.append(scope) ldap_conn.unbind() return { 'scopes': scopes } async def get_all_users(self, ldap_conn): """ Return all users cn that `username` has in `scope`. Optionally also search by `groups`. """ r = ldap_conn.search( self.users_filter(), "(objectClass=organizationalPerson)", search_scope=LEVEL, attributes=['mail'] ) if r: users = ldap_conn.get_response(r)[0] return [user['attributes']['mail'][0] for user in users] async def getScopeUsers(self, scope): """ Retorna tots els usuaris que pertanyen a un scope Nota: es pot millorar. Recorre dos cops tots els usuaris. Un cop per obtenir-los tots i un altre per filtrar segons si l'usuari pertany o no """ ldap_conn = self.bind_root_readonly() all_users_ids = await self.get_all_users(ldap_conn) users = [] for user_id in all_users_ids: user_dn = self.user_filter.format(username=user_id) roles = await self.get_user_roles(ldap_conn, scope, user_dn) if roles: user = { 'id': user_id, 'roles': roles } users.append(user) ldap_conn.unbind() return { 'users': users }
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=3) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=True) def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_wrong_assertion(self): ok = False try: result = self.connection.search(search_base=test_base, search_filter='(xxx=yyy)', attributes=[test_name_attr]) except LDAPException: ok = True self.assertTrue(ok) def test_wrong_attribute(self): ok = False try: result = self.connection.search(search_base=test_base, search_filter='(cn=yyy)', attributes=[test_name_attr, 'xxx']) except LDAPException: ok = True self.assertTrue(ok) def test_wrong_object_class_add(self): ok = False try: result = self.connection.add(dn_for_test(test_base, 'test-add-operation-wrong'), 'iNetOrgPerson', {'objectClass': ['iNetOrgPerson', 'xxx'], 'sn': 'test-add', test_name_attr: 'test-add-operation'}) except LDAPException: ok = True self.assertTrue(ok) def test_valid_assertion(self): result = self.connection.search(search_base=test_base, search_filter='(cn=test*)', attributes=[test_name_attr]) 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.assertTrue(len(response) > 1) def test_valid_attribute(self): result = self.connection.search(search_base=test_base, search_filter='(cn=test*)', attributes=[test_name_attr, 'givenName']) 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.assertTrue(len(response) > 1) def test_valid_object_class_add(self): result = self.connection.add(dn_for_test(test_base, 'test-add-operation-check-names'), 'iNetOrgPerson', {'objectClass': ['iNetOrgPerson', 'Person'], 'sn': 'test-add', test_name_attr: 'test-add-operation-check-names'}) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'entryAlreadyExists'])
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True)) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1') def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_modify_dn_operation(self): result = self.connection.delete(dn_for_test(test_base, 'test-add-modified-dn')) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'noSuchObject']) result = self.connection.delete(dn_for_test(test_base, 'test-add-for-modify-dn')) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'noSuchObject']) result = self.connection.add(dn_for_test(test_base, 'test-add-for-modify-dn'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-compare', 'givenName': 'modify-dn'}) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'entryAlreadyExists']) result = self.connection.modify_dn(dn_for_test(test_base, 'test-add-for-modify-dn'), test_name_attr + '=test-add-modified-dn') if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'noSuchObject']) def test_move_dn(self): result = self.connection.delete(dn_for_test(test_base, 'test-add-for-move-dn')) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'noSuchObject']) result = self.connection.add(dn_for_test(test_base, 'test-add-for-move-dn'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-add-for-move-dn', 'givenName': 'move-dn'}) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'entryAlreadyExists']) result = self.connection.delete(dn_for_test(test_moved, 'test-add-for-move-dn')) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['success', 'noSuchObject', 'busy']) result = self.connection.modify_dn(dn_for_test(test_base, 'test-add-for-move-dn'), test_name_attr + '=test-add-for-move-dn', new_superior=test_moved) if not isinstance(result, bool): response, result = self.connection.get_response(result) else: response = self.connection.response result = self.connection.result self.assertTrue(result['description'] in ['other', 'success', 'entryAlreadyExists', 'noSuchObject'])
class Test(unittest.TestCase): def setUp(self): server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info) self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=test_check_names) result = self.connection.add(dn_for_test(test_base, 'test-search-(parentheses)'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-search-(parentheses)', 'loginGraceLimit': 10}) if not isinstance(result, bool): self.connection.get_response(result) def tearDown(self): self.connection.unbind() if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED: self.connection.strategy.terminate() self.assertFalse(self.connection.bound) def test_search_exact_match(self): result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=test-add-operation)', attributes=[test_name_attr, 'givenName', 'jpegPhoto']) 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) def test_search_extensible_match(self): result = self.connection.search(search_base=test_base, search_filter='(&(o:dn:=test)(objectclass=inetOrgPerson))', attributes=[test_name_attr, 'givenName', '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.assertTrue(len(response) > 8) def test_search_present(self): result = self.connection.search(search_base=test_base, search_filter='(objectClass=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName', 'jpegPhoto']) 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.assertTrue(len(response) > 9) def test_search_substring_many(self): result = self.connection.search(search_base=test_base, search_filter='(sn=t*)', attributes=[test_name_attr, 'givenName', '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.assertTrue(len(response) > 8) def test_search_substring_one(self): result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=*y)', attributes=[test_name_attr, 'givenName', '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.assertTrue(len(response) > 1) def test_search_raw(self): result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName', 'photo']) 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.assertTrue(len(response) > 8) def test_search_with_operational_attributes(self): result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=test-add-operation)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName', 'photo'], get_operational_attributes=True) 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(response[0]['attributes']['entryDN'][0], dn_for_test(test_base, 'test-add-operation')) def test_search_simple_paged(self): paged_size = 1 total_entries = 0 result = self.connection.search(search_base=test_base, search_filter='(objectClass=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName'], paged_size=paged_size) 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), paged_size) total_entries += len(response) cookie = result['controls']['1.2.840.113556.1.4.319']['value']['cookie'] while cookie: paged_size += 1 result = self.connection.search(search_base=test_base, search_filter='(objectClass=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName'], paged_size=paged_size, paged_cookie=cookie) 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') total_entries += len(response) self.assertTrue(len(response) <= paged_size) cookie = result['controls']['1.2.840.113556.1.4.319']['value']['cookie'] self.assertTrue(total_entries > 9) 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_integer_exact_match(self): result = self.connection.search(search_base=test_base, search_filter='(loginGraceLimit=10)', attributes=[test_name_attr, 'loginGraceLimit']) 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), 2) def test_search_integer_less_than(self): result = self.connection.search(search_base=test_base, search_filter='(loginGraceLimit<=11)', attributes=[test_name_attr, 'loginGraceLimit']) 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), 2) def test_search_integer_greater_than(self): result = self.connection.search(search_base=test_base, search_filter='(loginGraceLimit>=9)', attributes=[test_name_attr, 'loginGraceLimit']) 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), 2)