diff options
Diffstat (limited to 'python/samba/tests/samba_tool/contact.py')
-rw-r--r-- | python/samba/tests/samba_tool/contact.py | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/python/samba/tests/samba_tool/contact.py b/python/samba/tests/samba_tool/contact.py new file mode 100644 index 0000000..2bec813 --- /dev/null +++ b/python/samba/tests/samba_tool/contact.py @@ -0,0 +1,468 @@ +# Unix SMB/CIFS implementation. +# +# Tests for samba-tool contact management commands +# +# Copyright (C) Bjoern Baumbach <bbaumbach@samba.org> 2019 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import ldb +from samba.tests.samba_tool.base import SambaToolCmdTest + +class ContactCmdTestCase(SambaToolCmdTest): + """Tests for samba-tool contact subcommands""" + contacts = [] + samdb = None + + def setUp(self): + super().setUp() + self.creds = "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"]) + self.samdb = self.getSamDB("-H", + "ldap://%s" % os.environ["DC_SERVER"], + self.creds) + contact = None + self.contacts = [] + + contact = self._randomContact({"expectedname": "contact1", + "name": "contact1"}) + self.contacts.append(contact) + + # No 'name' is given here, so the name will be made from givenname. + contact = self._randomContact({"expectedname": "contact2", + "givenName": "contact2"}) + self.contacts.append(contact) + + contact = self._randomContact({"expectedname": "contact3", + "name": "contact3", + "displayName": "contact3displayname", + "givenName": "not_contact3", + "initials": "I", + "sn": "not_contact3", + "mobile": "12345"}) + self.contacts.append(contact) + + # No 'name' is given here, so the name will be made from the the + # sn, initials and givenName attributes. + contact = self._randomContact({"expectedname": "James T. Kirk", + "sn": "Kirk", + "initials": "T", + "givenName": "James"}) + self.contacts.append(contact) + + # setup the 4 contacts and ensure they are correct + for contact in self.contacts: + (result, out, err) = self._create_contact(contact) + + self.assertCmdSuccess(result, out, err) + self.assertNotIn( + "ERROR", err, "There shouldn't be any error message") + self.assertIn("Contact '%s' added successfully" % + contact["expectedname"], out) + + found = self._find_contact(contact["expectedname"]) + + self.assertIsNotNone(found) + + contactname = contact["expectedname"] + self.assertEqual("%s" % found.get("name"), contactname) + self.assertEqual("%s" % found.get("description"), + contact["description"]) + + def tearDown(self): + super().tearDown() + # clean up all the left over contacts, just in case + for contact in self.contacts: + if self._find_contact(contact["expectedname"]): + (result, out, err) = self.runsubcmd( + "contact", "delete", "%s" % contact["expectedname"]) + self.assertCmdSuccess(result, out, err, + "Failed to delete contact '%s'" % + contact["expectedname"]) + + def test_newcontact(self): + """This tests the "contact create" and "contact delete" commands""" + # try to create all the contacts again, this should fail + for contact in self.contacts: + (result, out, err) = self._create_contact(contact) + self.assertCmdFail(result, "Succeeded to create existing contact") + self.assertIn("already exists", err) + + # try to delete all the contacts we just added + for contact in self.contacts: + (result, out, err) = self.runsubcmd("contact", "delete", "%s" % + contact["expectedname"]) + self.assertCmdSuccess(result, out, err, + "Failed to delete contact '%s'" % + contact["expectedname"]) + found = self._find_contact(contact["expectedname"]) + self.assertIsNone(found, + "Deleted contact '%s' still exists" % + contact["expectedname"]) + + # test creating contacts in an specified OU + parentou = self._randomOU({"name": "testOU"}) + (result, out, err) = self._create_ou(parentou) + self.assertCmdSuccess(result, out, err) + + for contact in self.contacts: + (result, out, err) = self._create_contact(contact, ou="OU=testOU") + + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "There shouldn't be any error message") + self.assertIn("Contact '%s' added successfully" % + contact["expectedname"], out) + + found = self._find_contact(contact["expectedname"]) + + contactname = contact["expectedname"] + self.assertEqual("%s" % found.get("name"), contactname) + self.assertEqual("%s" % found.get("description"), + contact["description"]) + + # try to delete all the contacts we just added, by DN + for contact in self.contacts: + expecteddn = ldb.Dn(self.samdb, + "CN=%s,OU=%s,%s" % + (contact["expectedname"], + parentou["name"], + self.samdb.domain_dn())) + (result, out, err) = self.runsubcmd("contact", "delete", "%s" % + expecteddn) + self.assertCmdSuccess(result, out, err, + "Failed to delete contact '%s'" % + contact["expectedname"]) + found = self._find_contact(contact["expectedname"]) + self.assertIsNone(found, + "Deleted contact '%s' still exists" % + contact["expectedname"]) + + (result, out, err) = self.runsubcmd("ou", "delete", + "OU=%s" % parentou["name"]) + self.assertCmdSuccess(result, out, err, + "Failed to delete ou '%s'" % parentou["name"]) + + # creating contacts, again for further tests + for contact in self.contacts: + (result, out, err) = self._create_contact(contact) + + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "There shouldn't be any error message") + self.assertIn("Contact '%s' added successfully" % + contact["expectedname"], out) + + found = self._find_contact(contact["expectedname"]) + + contactname = contact["expectedname"] + self.assertEqual("%s" % found.get("name"), contactname) + self.assertEqual("%s" % found.get("description"), + contact["description"]) + + def test_list(self): + (result, out, err) = self.runsubcmd("contact", "list") + self.assertCmdSuccess(result, out, err, "Error running list") + + search_filter = "(objectClass=contact)" + contactlist = self.samdb.search(base=self.samdb.domain_dn(), + scope=ldb.SCOPE_SUBTREE, + expression=search_filter, + attrs=["name"]) + + self.assertTrue(len(contactlist) > 0, "no contacts found in samdb") + + for contactobj in contactlist: + name = contactobj.get("name", idx=0) + self.assertMatch(out, str(name), + "contact '%s' not found" % name) + + def test_list_full_dn(self): + (result, out, err) = self.runsubcmd("contact", "list", "--full-dn") + self.assertCmdSuccess(result, out, err, "Error running list") + + search_filter = "(objectClass=contact)" + contactlist = self.samdb.search(base=self.samdb.domain_dn(), + scope=ldb.SCOPE_SUBTREE, + expression=search_filter, + attrs=["dn"]) + + self.assertTrue(len(contactlist) > 0, "no contacts found in samdb") + + for contactobj in contactlist: + self.assertMatch(out, str(contactobj.dn), + "contact '%s' not found" % str(contactobj.dn)) + + def test_list_base_dn(self): + base_dn = str(self.samdb.domain_dn()) + (result, out, err) = self.runsubcmd("contact", "list", + "-b", base_dn) + self.assertCmdSuccess(result, out, err, "Error running list") + + search_filter = "(objectClass=contact)" + contactlist = self.samdb.search(base=base_dn, + scope=ldb.SCOPE_SUBTREE, + expression=search_filter, + attrs=["name"]) + + self.assertTrue(len(contactlist) > 0, "no contacts found in samdb") + + for contactobj in contactlist: + name = contactobj.get("name", idx=0) + self.assertMatch(out, str(name), + "contact '%s' not found" % name) + + def test_move(self): + parentou = self._randomOU({"name": "parentOU"}) + (result, out, err) = self._create_ou(parentou) + self.assertCmdSuccess(result, out, err) + + for contact in self.contacts: + olddn = self._find_contact(contact["expectedname"]).get("dn") + + (result, out, err) = self.runsubcmd("contact", "move", + "%s" % contact["expectedname"], + "OU=%s" % parentou["name"]) + self.assertCmdSuccess(result, out, err, + "Failed to move contact '%s'" % + contact["expectedname"]) + self.assertEqual(err, "", "There shouldn't be any error message") + self.assertIn('Moved contact "%s"' % contact["expectedname"], out) + + found = self._find_contact(contact["expectedname"]) + self.assertNotEqual(found.get("dn"), olddn, + ("Moved contact '%s' still exists with the " + "same dn" % contact["expectedname"])) + contactname = contact["expectedname"] + newexpecteddn = ldb.Dn(self.samdb, + "CN=%s,OU=%s,%s" % + (contactname, + parentou["name"], + self.samdb.domain_dn())) + self.assertEqual(found.get("dn"), newexpecteddn, + "Moved contact '%s' does not exist" % + contact["expectedname"]) + + (result, out, err) = self.runsubcmd("contact", "move", + "%s" % contact["expectedname"], + "%s" % olddn.parent()) + self.assertCmdSuccess(result, out, err, + "Failed to move contact '%s'" % + contact["expectedname"]) + + (result, out, err) = self.runsubcmd("ou", "delete", + "OU=%s" % parentou["name"]) + self.assertCmdSuccess(result, out, err, + "Failed to delete ou '%s'" % parentou["name"]) + + def test_rename_givenname_initials_surname(self): + """rename and remove given name, initials and surname for all contacts""" + for contact in self.contacts: + name = contact["name"] if "name" in contact else contact["expectedname"] + + new_givenname = "new_given_name_of_" + name + new_initials = "A" + new_surname = "new_surname_of_" + name + new_cn = "new_cn_of_" + name + expected_cn = "%s %s. %s" % (new_givenname, new_initials, new_surname) + + # rename given name, initials and surname + (result, out, err) = self.runsubcmd("contact", "rename", name, + "--reset-cn", + "--surname=%s" % new_surname, + "--initials=%s" % new_initials, + "--given-name=%s" % new_givenname) + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "Shouldn't be any error messages") + self.assertIn('successfully', out) + + found = self._find_contact(expected_cn) + self.assertEqual("%s" % found.get("givenName"), new_givenname) + self.assertEqual("%s" % found.get("initials"), new_initials) + self.assertEqual("%s" % found.get("sn"), new_surname) + self.assertEqual("%s" % found.get("name"), expected_cn) + self.assertEqual("%s" % found.get("cn"), expected_cn) + + # remove given name, initials and surname + # (must force new cn, because en empty new CN throws an error) + (result, out, err) = self.runsubcmd("contact", "rename", expected_cn, + "--force-new-cn=%s" % expected_cn, + "--surname=", + "--initials=", + "--given-name=") + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "Shouldn't be any error messages") + self.assertIn('successfully', out) + + found = self._find_contact(expected_cn) + self.assertEqual(found.get("givenName"), None) + self.assertEqual(found.get("initials"), None) + self.assertEqual(found.get("sn"), None) + + # reset changes (initials are already removed) + old_surname = contact["sn"] if "sn" in contact else "" + old_initials = contact["initials"] if "initials" in contact else "" + old_givenname = contact["givenName"] if "givenName" in contact else "" + old_cn = contact["cn"] if "cn" in contact else name + (result, out, err) = self.runsubcmd("contact", "rename", expected_cn, + "--force-new-cn=%s" % old_cn, + "--surname=%s" % old_surname, + "--initials=%s" % old_initials, + "--given-name=%s" % old_givenname) + self.assertCmdSuccess(result, out, err) + + def test_rename_cn(self): + """rename and try to remove the cn of all contacts""" + for contact in self.contacts: + name = contact["name"] if "name" in contact else contact["expectedname"] + new_cn = "new_cn_of_" + name + + # rename cn + (result, out, err) = self.runsubcmd("contact", "rename", name, + "--force-new-cn=%s" % new_cn) + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "Shouldn't be any error messages") + self.assertIn('successfully', out) + + found = self._find_contact(new_cn) + self.assertEqual("%s" % found.get("cn"), new_cn) + + # trying to remove cn (throws an error) + (result, out, err) = self.runsubcmd("contact", "rename", new_cn, + "--force-new-cn=") + self.assertCmdFail(result) + self.assertIn('Failed to rename contact', err) + self.assertIn("delete protected attribute", err) + + # reset changes (cn must be the name) + (result, out, err) = self.runsubcmd("contact", "rename", new_cn, + "--force-new-cn=%s" % name) + self.assertCmdSuccess(result, out, err) + + + def test_rename_mailaddress_displayname(self): + """rename and remove the mail and the displayname attribute of all contacts""" + for contact in self.contacts: + name = contact["name"] if "name" in contact else contact["expectedname"] + new_mail = "new_mailaddress_of_" + name + new_displayname = "new displayname of " + name + + # change mail and displayname + (result, out, err) = self.runsubcmd("contact", "rename", name, + "--mail-address=%s" + % new_mail, + "--display-name=%s" + % new_displayname) + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "Shouldn't be any error messages") + self.assertIn('successfully', out) + + found = self._find_contact(name) + self.assertEqual("%s" % found.get("mail"), new_mail) + self.assertEqual("%s" % found.get("displayName"), new_displayname) + + # remove mail and displayname + (result, out, err) = self.runsubcmd("contact", "rename", name, + "--mail-address=", + "--display-name=") + self.assertCmdSuccess(result, out, err) + self.assertEqual(err, "", "Shouldn't be any error messages") + self.assertIn('successfully', out) + + found = self._find_contact(name) + self.assertEqual(found.get("mail"), None) + self.assertEqual(found.get("displayName"), None) + + # reset changes + old_mail = contact["givenName"] if "givenName" in contact else "" + old_displayname = contact["cn"] if "cn" in contact else "" + (result, out, err) = self.runsubcmd("contact", "rename", name, + "--mail-address=%s" % old_mail, + "--display-name=%s" % old_displayname) + self.assertCmdSuccess(result, out, err) + + def _randomContact(self, base=None): + """Create a contact with random attribute values, you can specify base + attributes""" + if base is None: + base = {} + + # No name attributes are given here, because the object name will + # be made from the sn, givenName and initials attributes, if no name + # is given. + contact = { + "description": self.randomName(count=100), + } + contact.update(base) + return contact + + def _randomOU(self, base=None): + """Create an ou with random attribute values, you can specify base + attributes.""" + if base is None: + base = {} + + ou = { + "name": self.randomName(), + "description": self.randomName(count=100), + } + ou.update(base) + return ou + + def _create_contact(self, contact, ou=None): + args = "" + + if "name" in contact: + args += '{0}'.format(contact['name']) + + args += ' {0}'.format(self.creds) + + if ou is not None: + args += ' --ou={0}'.format(ou) + + if "description" in contact: + args += ' --description={0}'.format(contact["description"]) + if "sn" in contact: + args += ' --surname={0}'.format(contact["sn"]) + if "initials" in contact: + args += ' --initials={0}'.format(contact["initials"]) + if "givenName" in contact: + args += ' --given-name={0}'.format(contact["givenName"]) + if "displayName" in contact: + args += ' --display-name={0}'.format(contact["displayName"]) + if "mobile" in contact: + args += ' --mobile-number={0}'.format(contact["mobile"]) + + args = args.split() + + return self.runsubcmd('contact', 'create', *args) + + def _create_ou(self, ou): + return self.runsubcmd("ou", + "create", + "OU=%s" % ou["name"], + "--description=%s" % ou["description"]) + + def _find_contact(self, name): + contactname = name + search_filter = ("(&(objectClass=contact)(name=%s))" % + ldb.binary_encode(contactname)) + contactlist = self.samdb.search(base=self.samdb.domain_dn(), + scope=ldb.SCOPE_SUBTREE, + expression=search_filter, + attrs=[]) + if contactlist: + return contactlist[0] + else: + return None |