def test_write_entries(): """ Test writing multiple entries into the same output. """ ent0 = LDAPEntry("cn=test0") ent0["cn"] = "test0" ent1 = LDAPEntry("cn=test1") ent1["cn"] = "test1" entries = (ent0, ent1) with StringIO() as out: ldif = LDIFWriter(out) ldif.write_entries(entries, write_version=False) content = out.getvalue() assert "dn: {0}".format(ent0.dn) in content assert "dn: {0}".format(ent1.dn) in content assert "cn: {0}".format(ent0["cn"][0]) in content assert "cn: {0}".format(ent1["cn"][0]) in content assert "version" not in content with StringIO() as out: ldif = LDIFWriter(out) ldif.write_entries(entries) content = out.getvalue() assert "dn: {0}".format(ent0.dn) in content assert "dn: {0}".format(ent1.dn) in content assert "version: 1" == content.split("\n")[0]
def test_equal(): """ Test equality check. """ entry1 = LDAPEntry("cn=test") entry2 = LDAPEntry("cn=test") entry3 = LDAPEntry("cn=test1") assert entry1 == entry2 assert not (entry1 == entry3) assert entry1 == {"dn": LDAPDN("cn=test")} assert not (entry1 == 2)
def test_equal(self): """ Test equality check. """ entry1 = LDAPEntry("cn=test") entry2 = LDAPEntry("cn=test") entry3 = LDAPEntry("cn=test1") self.assertTrue(entry1 == entry2) self.assertFalse(entry1 == entry3) self.assertTrue(entry1 == dict()) self.assertFalse(entry1 == 2)
def test_obj_err(self): """ Test object class violation error. """ entry = LDAPEntry("cn=async_test,%s" % self.basedn) entry["cn"] = ["async_test"] with (yield self.client.connect(True, ioloop=self.io_loop)) as conn: with pytest.raises(bonsai.errors.ObjectClassViolation): yield conn.add(entry)
def test_modify_and_rename(self): """ Test modifying and renaming an LDAP entry. """ with (yield self.client.connect(True, ioloop=self.io_loop)) as conn: entry = LDAPEntry("cn=async_test,%s" % self.basedn) entry["objectclass"] = [ "top", "inetOrgPerson", "person", "organizationalPerson", ] entry["sn"] = "async_test" oldname = "cn=async_test,%s" % self.basedn newname = "cn=async_test2,%s" % self.basedn res = yield conn.search(newname, 0) if res: yield res[0].delete() try: yield conn.add(entry) except bonsai.errors.AlreadyExists: yield conn.delete(entry.dn) yield conn.add(entry) except: self.fail("Unexpected error.") entry["sn"] = "async_test2" yield entry.modify() yield entry.rename(newname) res = yield conn.search(entry.dn, 0, attrlist=["sn"]) assert entry["sn"] == res[0]["sn"] res = yield conn.search(oldname, 0) assert res == [] yield conn.delete(entry.dn)
def test_write_changes(): """ Test writing LDIF changes of an LDAP Entry. """ ent = LDAPEntry("cn=test") ent["cn"] = "test" ent["sn"] = ["sntest1", "sntest2"] ent.change_attribute("givenName", LDAPModOp.REPLACE, "test") ent.change_attribute("uidNumber", LDAPModOp.DELETE, 0) ent.change_attribute("gidNumber", LDAPModOp.DELETE) with StringIO() as out: ldif = LDIFWriter(out) ldif.write_changes(ent) content = out.getvalue() lines = content.split("\n") assert "dn: {0}".format(ent.dn) == lines.pop(0) # First line. assert "changetype: modify" == lines.pop(0) # Second line. assert "add: cn" in lines assert "cn: {0}".format(ent["cn"][0]) == lines[lines.index("add: cn") + 1] assert "add: sn" in lines assert set(ent["sn"]) == {lin.split("sn: ")[1] for lin in lines if "sn: " in lin} assert "replace: givenName" in lines assert ( "givenName: {0}".format(ent["givenName"][0]) == lines[lines.index("replace: givenName") + 1] ) assert "delete: uidNumber" in lines assert "uidNumber: 0" == lines[lines.index("delete: uidNumber") + 1] assert "delete: gidNumber" in lines # Remove the key entirely. assert "-" == lines[lines.index("delete: gidNumber") + 1]
def test_sync_operations(self): """ Test LDAPEntry's add, modify and delete synchronous operations. """ entry = LDAPEntry("cn=test,%s" % self.basedn) self.client.set_credentials(*self.creds) with self.client.connect() as conn: entry['objectclass'] = [ 'top', 'inetOrgPerson', 'person', 'organizationalPerson' ] self.assertRaises(bonsai.ObjectClassViolation, lambda: conn.add(entry)) entry['sn'] = 'test' try: conn.add(entry) except bonsai.AlreadyExists: conn.delete(entry.dn) conn.add(entry) except: self.fail("Adding LDAPEntry to the server is failed.") entry['sn'] = "Test_modify" try: entry.modify() except: self.fail("Modify failed.") obj = conn.search("cn=test,%s" % self.basedn, 0)[0] self.assertEqual(entry['sn'], obj['sn']) try: entry.delete() except: self.fail("Delete failed.")
def test_keys(): """ Test LDAPEntry's keys method. """ entry = LDAPEntry("cn=test") entry["cn"] = "test" entry["sn"] = "Test" assert set(entry.keys()) == set(["dn", "cn", "sn"]) assert set(entry.keys(exclude_dn=True)) == set(["cn", "sn"])
def test_write_entry(): """ Test serialising an LDAP entry. """ ent = LDAPEntry("cn=test") ent["cn"] = "test" ent["jpegPhoto"] = b"1223122130008283938282931232" ent["sn"] = "test😊" ent["sn"].append(" test2") with StringIO() as out: ldif = LDIFWriter(out, max_length=32) ldif.write_entry(ent) content = out.getvalue() contlines = content.split("\n") surnames = { b64decode(line.split(":: ")[1]).decode("UTF-8") for line in contlines if "sn" in line } jpeg_lines = [] for idx, line in enumerate(contlines): if "jpegPhoto::" in line: jpeg_lines.append(line.split(" ")[1]) jpeg_lines.append(contlines[idx + 1][1:]) jpegPhoto = b64decode("".join(jpeg_lines)) assert all(len(line) <= 32 for line in contlines) assert "dn: {0}".format(ent.dn) == contlines[0] assert "cn: {0}\n".format(ent["cn"][0]) in content assert content.count("sn:: ") == 2 assert surnames == set(ent["sn"]) assert content.count("jpegPhoto:: ") == 1 assert jpegPhoto == ent["jpegPhoto"][0]
async def test_obj_err(client, basedn): """ Test object class violation error. """ entry = LDAPEntry("cn=async_test,%s" % basedn) entry["cn"] = ["async_test"] with pytest.raises(bonsai.errors.ObjectClassViolation): async with client.connect(True) as conn: await conn.add(entry)
def test_change_attribute(client): """ Test change_attribute method. """ user_dn = "cn=sam,ou=nerdherd,dc=bonsai,dc=test" if sys.platform == "win32": multiattr = "otherTelephone" else: multiattr = "mail" with client.connect() as conn: entry = LDAPEntry(user_dn, conn) entry.change_attribute("mail", LDAPModOp.ADD, "*****@*****.**") assert entry["mail"].status == 1 entry.modify() assert conn.search(user_dn, 0)[0]["mail"][0] == "*****@*****.**" entry.change_attribute("mail", 1, "*****@*****.**") assert entry["mail"].status == 1 entry.modify() with pytest.raises(KeyError): _ = conn.search(user_dn, 0)[0]["mail"] entry.change_attribute(multiattr, LDAPModOp.REPLACE, "*****@*****.**", "*****@*****.**") assert entry[multiattr].status == 2 entry.modify() res = conn.search(user_dn, 0)[0][multiattr] assert "*****@*****.**" in res assert "*****@*****.**" in res entry.change_attribute(multiattr, 1, "*****@*****.**") entry.change_attribute(multiattr, 0, "*****@*****.**") entry.modify() res = conn.search(user_dn, 0)[0][multiattr] assert "*****@*****.**" in res assert "*****@*****.**" in res entry.change_attribute(multiattr, 1) entry.modify() assert multiattr not in conn.search(user_dn, 0)[0].keys()
async def test_modify_and_rename(client, basedn): """ Test modifying and renaming LDAP entry. """ async with client.connect(True) as conn: entry = LDAPEntry("cn=async_test,%s" % basedn) entry["objectclass"] = [ "top", "inetOrgPerson", "person", "organizationalPerson", ] entry["sn"] = "async_test" oldname = "cn=async_test,%s" % basedn newname = "cn=async_test2,%s" % basedn res = await conn.search(newname, 0) if res: await res[0].delete() try: await conn.add(entry) except bonsai.errors.AlreadyExists: await conn.delete(entry.dn) await conn.add(entry) except: pytest.fail("Unexpected error.") entry["sn"] = "async_test2" await entry.modify() await entry.rename(newname) res = await conn.search(entry.dn, 0, attrlist=["sn"]) assert entry["sn"] == res[0]["sn"] res = await conn.search(oldname, 0) assert res == [] await conn.delete(entry.dn)
def test_modify_and_rename(self): """ Test modifying and renaming LDAP entry. """ with (yield from self.client.connect(True)) as conn: entry = LDAPEntry("cn=async_test,%s" % self.basedn) entry['objectclass'] = [ 'top', 'inetOrgPerson', 'person', 'organizationalPerson' ] entry['sn'] = "async_test" oldname = "cn=async_test,%s" % self.basedn newname = "cn=async_test2,%s" % self.basedn res = yield from conn.search(newname, 0) if res: yield from res[0].delete() try: yield from conn.add(entry) except bonsai.errors.AlreadyExists: yield from conn.delete(entry.dn) yield from conn.add(entry) except: self.fail("Unexpected error.") entry['sn'] = "async_test2" yield from entry.modify() yield from entry.rename(newname) res = yield from conn.search(entry.dn, 0, attrlist=['sn']) self.assertEqual(entry['sn'], res[0]['sn']) res = yield from conn.search(oldname, 0) self.assertEqual(res, []) yield from conn.delete(entry.dn)
def test_clear(self): """ Test LDAPEntry's clear method. """ entry = LDAPEntry("cn=test") entry['sn'] = ['test1', 'test2'] entry['gn'] = ['test3'] entry.clear() self.assertDictEqual(entry, {}) self.assertEqual(entry.dn, "cn=test")
def test_clear(): """ Test LDAPEntry's clear method. """ entry = LDAPEntry("cn=test") entry["sn"] = ["test1", "test2"] entry["gn"] = ["test3"] entry.clear() assert entry == {"dn": LDAPDN("cn=test")} assert entry.dn == "cn=test"
def test_pop(self): """ Test LDAPEntry's pop method. """ entry = LDAPEntry("cn=test") entry['test'] = "test" self.assertRaises(TypeError, entry.pop) self.assertRaises(TypeError, lambda: entry.pop('t', 2, 3)) self.assertRaises(KeyError, lambda: entry.pop('t')) self.assertEqual(entry.pop("test"), ["test"]) self.assertEqual(entry.pop("test", None), None)
def test_dn_attr(basedn): """ Test LDAPEntry's DN attribute. """ entry = LDAPEntry("cn=test,%s" % basedn) entry.dn = "cn=test" assert str(entry.dn) == "cn=test" with pytest.raises(TypeError): del entry.dn with pytest.raises(TypeError): entry["dn"] = 5
def test_append_extend(): """ Test append and extend methods of LDAPEntry's attribute. """ entry = LDAPEntry("cn=test") entry["givenName"] = "test" entry["givenname"].append("test2") assert entry["givenname"] == ["test", "test2"] assert entry["givenname"][0] == "test" with pytest.raises(ValueError): entry["GivenName"].extend(["teSt", "test3"])
def test_obj_err(self): entry = LDAPEntry("cn=async_test,%s" % self.basedn) entry['objectclass'] = ['top', 'inetOrgPerson', 'person', 'organizationalPerson'] @asyncio_test def err(): with (yield from self.client.connect(True)) as conn: yield from conn.add(entry) self.assertRaises(bonsai.errors.ObjectClassViolation, err)
def test_append_extend(self): """ Test append and extend methods of LDAPEntry's attribute. """ entry = LDAPEntry("cn=test") entry['givenName'] = "test" entry['givenname'].append("test2") self.assertListEqual(entry['givenname'], ["test", "test2"]) self.assertEqual(entry['givenname'][0], "test") self.assertRaises(ValueError, lambda: entry['GivenName'].extend(['teSt', "test3"]))
def test_special_char(client, basedn): """ Test adding entry with special character in its DN. """ with client.connect() as conn: entry = LDAPEntry(r"cn=test\, *\+withspec,%s" % basedn) entry["objectclass"] = ["top", "inetOrgPerson"] entry["sn"] = "Test,*special" conn.add(entry) result = conn.search(basedn, 1) entry.delete() assert entry.dn in [res.dn for res in result]
def _construct_ldap_entries(self): tmp = list() for entry in self.sample_ldap: new_entry = LDAPEntry(entry['dn']) for key, value in entry.items(): if key == 'dn': continue new_entry[key] = value tmp.append(new_entry) self.sample_ldap = tmp
def test_popitem(): """ Test LDAPEntry's popitem method. """ entry = LDAPEntry("cn=test") entry["test"] = "test" entry["test2"] = "test" item = entry.popitem() assert len(item) == 2 assert item[0] not in entry entry[item[0]] = item[1] assert entry[item[0]] == item[1]
def test_popitem(self): """ Test LDAPEntry's popitem method. """ entry = LDAPEntry("cn=test") entry['test'] = "test" entry['test2'] = 'test' item = entry.popitem() self.assertEqual(len(item), 2) self.assertNotIn(item[0], entry) entry[item[0]] = item[1] self.assertEqual(entry[item[0]], item[1])
def test_obj_err(self): """ Test object class violation error. """ entry = LDAPEntry("cn=async_test,%s" % self.basedn) entry['cn'] = ['async_test'] @asyncio_test def err(): with (yield from self.client.connect(True)) as conn: yield from conn.add(entry) self.assertRaises(bonsai.errors.ObjectClassViolation, err)
def register_vip(username, firstname, surname, password, department = "floor1", address="Nowhere", phone=102): if len(firstname) > 24 or len(surname) > 24: return None if department not in VipDepartmentList: return None # Instantiate connection client, conn = instantiate_connection() # Check if user already exists FILTER = f'(cn={sanitize(username)})' response = conn.search(LDAPBASE_DN , 2, FILTER) conn.close() nb_results = len(response) if nb_results >= 1: return None else: # Generate Key Pair (private_key, public_key) = generateKeyPair() enc_address = encodeUsingKey(public_key, str.encode(address)).hex() hash_pass = hash_password(password) # Connect using admin account server, conn = instantiate_connection() # Build user DN USER_DN = f'cn={username},ou=people,{LDAPBASE_DN}' # Build user entry user = LDAPEntry(USER_DN) user['objectClass'] = ['person', 'inetOrgPerson', 'ldapPublicKey'] user['givenName'] = firstname user['sn'] = surname user['homePostalAddress'] = enc_address user['telephoneNumber'] = int(phone) user['departmentNumber'] = department user['userPassword'] = hash_pass # Handle intern keys and non intern keys user['sshPublicKey'] = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) print_priv = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) add_sucess = conn.add(user) conn.close() if (add_sucess): return print_priv else: return None
def test_unicode(client, basedn): """ Test adding entry with special character in its DN. """ with client.connect() as conn: dname = "cn=test_µčབྷñ,%s" % basedn entry = LDAPEntry(dname) entry["objectclass"] = ["top", "inetOrgPerson"] entry["sn"] = "unicode_µčབྷñ" conn.add(entry) result = conn.search(dname, 0) entry.delete() assert dname in [res.dn for res in result]
def test_set_get(): """ Test LDAPEntry's SetItem, GetItem and get methods. """ entry = LDAPEntry("cn=test") entry["sn"] = "Test" assert entry == {"dn": LDAPDN("cn=test"), "sn": ["Test"]} entry["givenname"] = "Test" assert entry.get("None") is None assert entry.get("GivenName") == entry["givenNAME"] del entry["sn"] with pytest.raises(KeyError): _ = entry["sn"]
def test_update(self): """ Test updating LDAPEntry object. """ entry = LDAPEntry("cn=test") entry.update({"GivenName": "test2", "mail": "test@mail"}) entry.update([("sn", "test")]) entry.update(uidnumber=1, gidnumber=1) self.assertEqual(entry['mail'], ['test@mail']) self.assertEqual(entry['givenname'], ['test2']) self.assertEqual(entry['sn'][0], 'test') self.assertEqual(entry['uidnumber'], [1]) self.assertEqual(entry['gidnumber'], [1])
def test_connection(self): """ Test set and get connection object form LDAPEntry. """ entry = LDAPEntry("cn=test,%s" % self.basedn) conn = self.client.connect() entry.connection = conn self.assertEqual(entry.connection, conn) def invalid_assign(): entry.connection = "string" self.assertRaises(TypeError, invalid_assign)