예제 #1
0
    def run(self,
            groupname,
            listofmembers,
            credopts=None,
            sambaopts=None,
            versionopts=None,
            H=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        try:
            samdb = SamDB(url=H,
                          session_info=system_session(),
                          credentials=creds,
                          lp=lp)
            groupmembers = listofmembers.split(',')
            samdb.add_remove_group_members(groupname,
                                           groupmembers,
                                           add_members_operation=True)
        except Exception, e:
            # FIXME: catch more specific exception
            raise CommandError(
                'Failed to add members "%s" to group "%s"' %
                (listofmembers, groupname), e)
예제 #2
0
파일: group.py 프로젝트: mattiasa/samba
    def run(self,
            groupname,
            listofmembers,
            credopts=None,
            sambaopts=None,
            versionopts=None,
            H=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        try:
            samdb = SamDB(url=H,
                          session_info=system_session(),
                          credentials=creds,
                          lp=lp)
            samdb.add_remove_group_members(groupname,
                                           listofmembers.split(","),
                                           add_members_operation=False)
        except Exception as e:
            # FIXME: Catch more specific exception
            raise CommandError(
                'Failed to remove members "%s" from group "%s"' %
                (listofmembers, groupname), e)
        self.outf.write("Removed members from group %s\n" % groupname)
예제 #3
0
    def run(self, groupname, listofmembers, credopts=None, sambaopts=None, versionopts=None, H=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        try:
            samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp)
            samdb.add_remove_group_members(groupname, listofmembers, add_members_operation=False)
        except Exception, e:
            # FIXME: Catch more specific exception
            raise CommandError('Failed to remove members "%s" from group "%s"' % (listofmembers, groupname), e)
예제 #4
0
파일: group.py 프로젝트: runt18/samba
    def run(self, groupname, listofmembers, credopts=None, sambaopts=None,
            versionopts=None, H=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        try:
            samdb = SamDB(url=H, session_info=system_session(),
                          credentials=creds, lp=lp)
            groupmembers = listofmembers.split(',')
            samdb.add_remove_group_members(groupname, groupmembers,
                    add_members_operation=True)
        except Exception, e:
            # FIXME: catch more specific exception
            raise CommandError('Failed to add members "{0!s}" to group "{1!s}"'.format(
                listofmembers, groupname), e)
예제 #5
0
    def run(self,
            groupname,
            listofmembers=None,
            credopts=None,
            sambaopts=None,
            versionopts=None,
            H=None,
            member_base_dn=None,
            member_dn=None,
            object_types="user,group,computer"):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        if member_dn is None and listofmembers is None:
            self.usage()
            raise CommandError(
                'Either listofmembers or --member-dn must be specified.')

        try:
            samdb = SamDB(url=H,
                          session_info=system_session(),
                          credentials=creds,
                          lp=lp)
            groupmembers = []
            if member_dn is not None:
                groupmembers += member_dn
            if listofmembers is not None:
                groupmembers += listofmembers.split(',')
            group_member_types = object_types.split(',')

            if member_base_dn is not None:
                member_base_dn = samdb.normalize_dn_in_domain(member_base_dn)

            samdb.add_remove_group_members(groupname,
                                           groupmembers,
                                           add_members_operation=False,
                                           member_types=group_member_types,
                                           member_base_dn=member_base_dn)
        except Exception as e:
            # FIXME: Catch more specific exception
            raise CommandError(
                'Failed to remove members %r from group "%s"' %
                (listofmembers, groupname), e)
        self.outf.write("Removed members from group %s\n" % groupname)
예제 #6
0
파일: group.py 프로젝트: ravikant86/samba
    def run(self,
            groupname,
            listofmembers,
            credopts=None,
            sambaopts=None,
            versionopts=None,
            H=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        try:
            samdb = SamDB(url=H,
                          session_info=system_session(),
                          credentials=creds,
                          lp=lp)
            samdb.add_remove_group_members(groupname,
                                           listofmembers,
                                           add_members_operation=False)
        except Exception, e:
            raise CommandError(
                'Failed to remove members "%s" from group "%s"' %
                (listofmembers, groupname), e)
예제 #7
0
class GroupAuditTests(AuditLogTestBase):
    def setUp(self):
        self.message_type = MSG_GROUP_LOG
        self.event_type = DSDB_GROUP_EVENT_NAME
        super(GroupAuditTests, self).setUp()

        self.server_ip = os.environ["SERVER_IP"]

        host = "ldap://%s" % os.environ["SERVER"]
        self.ldb = SamDB(url=host,
                         session_info=system_session(),
                         credentials=self.get_credentials(),
                         lp=self.get_loadparm())
        self.server = os.environ["SERVER"]

        # Gets back the basedn
        self.base_dn = self.ldb.domain_dn()

        # Get the old "dSHeuristics" if it was set
        dsheuristics = self.ldb.get_dsheuristics()

        # Set the "dSHeuristics" to activate the correct "userPassword"
        # behaviour
        self.ldb.set_dsheuristics("000000001")

        # Reset the "dSHeuristics" as they were before
        self.addCleanup(self.ldb.set_dsheuristics, dsheuristics)

        # Get the old "minPwdAge"
        minPwdAge = self.ldb.get_minPwdAge()

        # Set it temporarily to "0"
        self.ldb.set_minPwdAge("0")
        self.base_dn = self.ldb.domain_dn()

        # Reset the "minPwdAge" as it was before
        self.addCleanup(self.ldb.set_minPwdAge, minPwdAge)

        # (Re)adds the test user USER_NAME with password USER_PASS
        self.ldb.add({
            "dn": "cn=" + USER_NAME + ",cn=users," + self.base_dn,
            "objectclass": "user",
            "sAMAccountName": USER_NAME,
            "userPassword": USER_PASS
        })
        self.ldb.newgroup(GROUP_NAME_01)
        self.ldb.newgroup(GROUP_NAME_02)

    def tearDown(self):
        super(GroupAuditTests, self).tearDown()
        delete_force(self.ldb, "cn=" + USER_NAME + ",cn=users," + self.base_dn)
        self.ldb.deletegroup(GROUP_NAME_01)
        self.ldb.deletegroup(GROUP_NAME_02)

    def test_add_and_remove_users_from_group(self):

        #
        # Wait for the primary group change for the created user.
        #
        messages = self.waitForMessages(2)
        print("Received %d messages" % len(messages))
        self.assertEquals(2, len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("PrimaryGroup", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        # Check the Add message for the new users primary group
        audit = messages[1]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        self.assertEquals(EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP,
                          audit["eventId"])
        #
        # Add the user to a group
        #
        self.discardMessages()

        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME])
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1, len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Add the user to another group
        #
        self.discardMessages()
        self.ldb.add_remove_group_members(GROUP_NAME_02, [USER_NAME])

        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1, len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_02 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Remove the user from a group
        #
        self.discardMessages()
        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME],
                                          add_members_operation=False)
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1, len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Removed", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Re-add the user to a group
        #
        self.discardMessages()
        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME])

        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1, len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

    def test_change_primary_group(self):

        #
        # Wait for the primary group change for the created user.
        #
        messages = self.waitForMessages(2)
        print("Received %d messages" % len(messages))
        self.assertEquals(2, len(messages),
                          "Did not receive the expected number of messages")

        # Check the PrimaryGroup message
        audit = messages[0]["groupChange"]

        self.assertEqual("PrimaryGroup", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        # Check the Add message for the new users primary group
        audit = messages[1]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        self.assertEquals(EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP,
                          audit["eventId"])

        #
        # Add the user to a group, the user needs to be a member of a group
        # before there primary group can be set to that group.
        #
        self.discardMessages()

        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME])
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1, len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")
        self.assertEquals(EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP,
                          audit["eventId"])

        #
        # Change the primary group of a user
        #
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        # get the primaryGroupToken of the group
        res = self.ldb.search(base=group_dn,
                              attrs=["primaryGroupToken"],
                              scope=ldb.SCOPE_BASE)
        group_id = res[0]["primaryGroupToken"]

        # set primaryGroupID attribute of the user to that group
        m = ldb.Message()
        m.dn = ldb.Dn(self.ldb, user_dn)
        m["primaryGroupID"] = ldb.MessageElement(group_id, FLAG_MOD_REPLACE,
                                                 "primaryGroupID")
        self.discardMessages()
        self.ldb.modify(m)

        #
        # Wait for the primary group change.
        # Will see the user removed from the new group
        #          the user added to their old primary group
        #          and a new primary group event.
        #
        messages = self.waitForMessages(3)
        print("Received %d messages" % len(messages))
        self.assertEquals(3, len(messages),
                          "Did not receive the expected number of messages")

        audit = messages[0]["groupChange"]
        self.assertEqual("Removed", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")
        self.assertEquals(EVT_ID_USER_REMOVED_FROM_GLOBAL_SEC_GROUP,
                          audit["eventId"])

        audit = messages[1]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")
        self.assertEquals(EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP,
                          audit["eventId"])

        audit = messages[2]["groupChange"]

        self.assertEqual("PrimaryGroup", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"], self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")
예제 #8
0
파일: rodc.py 프로젝트: zhoury14/samba
class RodcCmdTestCase(SambaToolCmdTest):
    def setUp(self):
        super(RodcCmdTestCase, self).setUp()
        self.lp = samba.param.LoadParm()
        self.lp.load(os.environ["SMB_CONF_PATH"])
        self.creds = Credentials()
        self.creds.set_username(os.environ["DC_USERNAME"])
        self.creds.set_password(os.environ["DC_PASSWORD"])
        self.creds.guess(self.lp)
        self.session = system_session()
        self.ldb = SamDB("ldap://" + os.environ["DC_SERVER"],
            session_info=self.session, credentials=self.creds,lp=self.lp)

        self.base_dn = self.ldb.domain_dn()

        self.ldb.newuser("sambatool1", "1qazXSW@")
        self.ldb.newuser("sambatool2", "2wsxCDE#")
        self.ldb.newuser("sambatool3", "3edcVFR$")
        self.ldb.newuser("sambatool4", "4rfvBGT%")
        self.ldb.newuser("sambatool5", "5tjbNHY*")
        self.ldb.newuser("sambatool6", "6yknMJU*")

        self.ldb.add_remove_group_members("Allowed RODC Password Replication Group",
                                          ["sambatool1", "sambatool2", "sambatool3",
                                           "sambatool4", "sambatool5"],
                                          add_members_operation=True)

    def tearDown(self):
        super(RodcCmdTestCase, self).tearDown()
        self.ldb.deleteuser("sambatool1")
        self.ldb.deleteuser("sambatool2")
        self.ldb.deleteuser("sambatool3")
        self.ldb.deleteuser("sambatool4")
        self.ldb.deleteuser("sambatool5")
        self.ldb.deleteuser("sambatool6")
        (result, out, err) = self.runsubcmd("drs", "replicate", "--local", "unused",
                                            os.environ["DC_SERVER"], self.base_dn)


    def test_single_by_account_name(self):
        (result, out, err) = self.runsubcmd("rodc", "preload", "sambatool1",
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertEqual(out, "Replicating DN CN=sambatool1,CN=Users,%s\n" % self.base_dn)
        self.assertEqual(err, "")

    def test_single_by_dn(self):
        (result, out, err) = self.runsubcmd("rodc", "preload", "cn=sambatool2,cn=users,%s" % self.base_dn,
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertEqual(out, "Replicating DN CN=sambatool2,CN=Users,%s\n" % self.base_dn)

    def test_multi_by_account_name(self):
        (result, out, err) = self.runsubcmd("rodc", "preload", "sambatool1", "sambatool2",
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertEqual(out, "Replicating DN CN=sambatool1,CN=Users,%s\nReplicating DN CN=sambatool2,CN=Users,%s\n" % (self.base_dn, self.base_dn))

    def test_multi_by_dn(self):
        (result, out, err) = self.runsubcmd("rodc", "preload", "cn=sambatool3,cn=users,%s" % self.base_dn, "cn=sambatool4,cn=users,%s" % self.base_dn,
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertEqual(out, "Replicating DN CN=sambatool3,CN=Users,%s\nReplicating DN CN=sambatool4,CN=Users,%s\n" % (self.base_dn, self.base_dn))

    def test_multi_in_file(self):
        tempf = os.path.join(self.tempdir, "accountlist")
        open(tempf, 'w').write("sambatool1\nsambatool2")
        (result, out, err) = self.runsubcmd("rodc", "preload", "--file", tempf,
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertEqual(out, "Replicating DN CN=sambatool1,CN=Users,%s\nReplicating DN CN=sambatool2,CN=Users,%s\n" % (self.base_dn, self.base_dn))
        os.unlink(tempf)

    def test_multi_with_missing_name_success(self):
        (result, out, err) = self.runsubcmd("rodc", "preload",
                                            "nonexistentuser1", "sambatool5",
                                            "nonexistentuser2",
                                            "--server", os.environ["DC_SERVER"],
                                            "--ignore-errors")
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertTrue(out.startswith("Replicating DN CN=sambatool5,CN=Users,%s\n"
                                       % self.base_dn))

    def test_multi_with_missing_name_failure(self):
        (result, out, err) = self.runsubcmd("rodc", "preload",
                                            "nonexistentuser1", "sambatool5",
                                            "nonexistentuser2",
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdFail(result, "ensuring rodc prefetch quit on missing user")

    def test_multi_without_group_success(self):
        (result, out, err) = self.runsubcmd("rodc", "preload",
                                            "sambatool6", "sambatool5",
                                            "--server", os.environ["DC_SERVER"],
                                            "--ignore-errors")
        self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully")
        self.assertTrue(out.startswith("Replicating DN CN=sambatool6,CN=Users,%s\n"
                                       "Replicating DN CN=sambatool5,CN=Users,%s\n"
                                       % (self.base_dn, self.base_dn)))

    def test_multi_without_group_failure(self):
        (result, out, err) = self.runsubcmd("rodc", "preload",
                                            "sambatool6", "sambatool5",
                                            "--server", os.environ["DC_SERVER"])
        self.assertCmdFail(result, "ensuring rodc prefetch quit on non-replicated user")
예제 #9
0
class DynamicTokenTest(samba.tests.TestCase):

    def get_creds(self, target_username, target_password):
        creds_tmp = Credentials()
        creds_tmp.set_username(target_username)
        creds_tmp.set_password(target_password)
        creds_tmp.set_domain(creds.get_domain())
        creds_tmp.set_realm(creds.get_realm())
        creds_tmp.set_workstation(creds.get_workstation())
        creds_tmp.set_gensec_features(creds_tmp.get_gensec_features()
                                      | gensec.FEATURE_SEAL)
        return creds_tmp

    def get_ldb_connection(self, target_username, target_password):
        creds_tmp = self.get_creds(target_username, target_password)
        ldb_target = SamDB(url=url, credentials=creds_tmp, lp=lp)
        return ldb_target

    def setUp(self):
        super(DynamicTokenTest, self).setUp()
        self.admin_ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp)

        self.base_dn = self.admin_ldb.domain_dn()

        self.test_user = "******"
        self.test_user_pass = "******"
        self.admin_ldb.newuser(self.test_user, self.test_user_pass)
        self.test_group0 = "tokengroups_group0"
        self.admin_ldb.newgroup(self.test_group0, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group0, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group0_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group0, [self.test_user],
                                       add_members_operation=True)

        self.test_group1 = "tokengroups_group1"
        self.admin_ldb.newgroup(self.test_group1, grouptype=dsdb.GTYPE_SECURITY_GLOBAL_GROUP)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group1, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group1_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group1, [self.test_user],
                                       add_members_operation=True)

        self.test_group2 = "tokengroups_group2"
        self.admin_ldb.newgroup(self.test_group2, grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group2, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group2_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group2, [self.test_user],
                                       add_members_operation=True)

        self.test_group3 = "tokengroups_group3"
        self.admin_ldb.newgroup(self.test_group3, grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group3, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group3_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group3, [self.test_group1],
                                       add_members_operation=True)

        self.test_group4 = "tokengroups_group4"
        self.admin_ldb.newgroup(self.test_group4, grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group4, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group4_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group4, [self.test_group3],
                                       add_members_operation=True)

        self.test_group5 = "tokengroups_group5"
        self.admin_ldb.newgroup(self.test_group5, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group5, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group5_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group5, [self.test_group4],
                                                add_members_operation=True)

        self.test_group6 = "tokengroups_group6"
        self.admin_ldb.newgroup(self.test_group6, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (self.test_group6, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        self.test_group6_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group6, [self.test_user],
                                                add_members_operation=True)

        self.ldb = self.get_ldb_connection(self.test_user, self.test_user_pass)

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        self.user_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["tokenGroups"][0])
        self.user_sid_dn = "<SID=%s>" % str(self.user_sid)

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=[])
        self.assertEquals(len(res), 1)

        self.test_user_dn = res[0].dn

        session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
                               AUTH_SESSION_INFO_AUTHENTICATED |
                               AUTH_SESSION_INFO_SIMPLE_PRIVILEGES)
        session = samba.auth.user_session(self.ldb, lp_ctx=lp, dn=self.user_sid_dn,
                                          session_info_flags=session_info_flags)

        token = session.security_token
        self.user_sids = []
        for s in token.sids:
            self.user_sids.append(str(s))

    def tearDown(self):
        super(DynamicTokenTest, self).tearDown()
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_user, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group0, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group1, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group2, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group3, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group4, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group5, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (self.test_group6, "cn=users", self.base_dn))

    def test_rootDSE_tokenGroups(self):
        """Testing rootDSE tokengroups against internal calculation"""
        if not url.startswith("ldap"):
            self.fail(msg="This test is only valid on ldap")

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        print("Getting tokenGroups from rootDSE")
        tokengroups = []
        for sid in res[0]['tokenGroups']:
            tokengroups.append(str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("tokengroups: %s" % tokengroups)
            print("calculated : %s" % self.user_sids)
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(msg="calculated groups don't match against rootDSE tokenGroups")

    def test_dn_tokenGroups(self):
        print("Getting tokenGroups from user DN")
        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroups']:
            dn_tokengroups.append(str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(dn_tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(msg="calculated groups don't match against user DN tokenGroups")

    def test_pac_groups(self):
        settings = {}
        settings["lp_ctx"] = lp
        settings["target_hostname"] = lp.get("netbios name")

        gensec_client = gensec.Security.start_client(settings)
        gensec_client.set_credentials(self.get_creds(self.test_user, self.test_user_pass))
        gensec_client.want_feature(gensec.FEATURE_SEAL)
        gensec_client.start_mech_by_sasl_name("GSSAPI")

        auth_context = AuthContext(lp_ctx=lp, ldb=self.ldb, methods=[])

        gensec_server = gensec.Security.start_server(settings, auth_context)
        machine_creds = Credentials()
        machine_creds.guess(lp)
        machine_creds.set_machine_account(lp)
        gensec_server.set_credentials(machine_creds)

        gensec_server.want_feature(gensec.FEATURE_SEAL)
        gensec_server.start_mech_by_sasl_name("GSSAPI")

        client_finished = False
        server_finished = False
        server_to_client = ""

        # Run the actual call loop.
        while client_finished == False and server_finished == False:
            if not client_finished:
                print "running client gensec_update"
                (client_finished, client_to_server) = gensec_client.update(server_to_client)
            if not server_finished:
                print "running server gensec_update"
                (server_finished, server_to_client) = gensec_server.update(client_to_server)

        session = gensec_server.session_info()

        token = session.security_token
        pac_sids = []
        for s in token.sids:
            pac_sids.append(str(s))

        sidset1 = set(pac_sids)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(msg="calculated groups don't match against user PAC tokenGroups")


    def test_tokenGroups_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result
        res = self.admin_ldb.search(base=self.base_dn, scope=ldb.SCOPE_SUBTREE,
                                    expression="(|(objectclass=user)(objectclass=group))",
                                    attrs=["memberOf"])
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(base=self.base_dn, scope=ldb.SCOPE_SUBTREE,
                                    expression="(objectclass=user)",
                                    attrs=["primaryGroupID"])
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "%s-%d" % (self.admin_ldb.get_domain_sid(), int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                             attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        wSet = set()
        wSet.add(self.test_user_dn.get_casefold())
        closure(vSet, wSet, aSet)
        wSet.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroups']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                         attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(wSet.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: %s" % wSet.difference(tokenGroupsSet))

        if len(tokenGroupsSet.difference(wSet)):
            self.fail(msg="additional tokenGroups: %s" % tokenGroupsSet.difference(wSet))


    def filtered_closure(self, wSet, filter_grouptype):
        res = self.admin_ldb.search(base=self.base_dn, scope=ldb.SCOPE_SUBTREE,
                                    expression="(|(objectclass=user)(objectclass=group))",
                                    attrs=["memberOf"])
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            vSet.add(obj.dn.get_casefold())
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(base=self.base_dn, scope=ldb.SCOPE_SUBTREE,
                                    expression="(objectclass=user)",
                                    attrs=["primaryGroupID"])
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "%s-%d" % (self.admin_ldb.get_domain_sid(), int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                             attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        uSet = set()
        for v in vSet:
            res_group = self.admin_ldb.search(base=v, scope=ldb.SCOPE_BASE,
                                              attrs=["groupType"],
                                              expression="objectClass=group")
            if len(res_group) == 1:
                if hex(int(res_group[0]["groupType"][0]) & 0x00000000FFFFFFFF) == hex(filter_grouptype):
                    uSet.add(v)
            else:
                uSet.add(v)

        closure(uSet, wSet, aSet)


    def test_tokenGroupsGlobalAndUniversal_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result

        # The variable names come from MS-ADTS May 15, 2014

        S = set()
        S.add(self.test_user_dn.get_casefold())

        self.filtered_closure(S, GTYPE_SECURITY_GLOBAL_GROUP)

        T = set()
        # Not really a SID, we do this on DNs...
        for sid in S:
            X = set()
            X.add(sid)
            self.filtered_closure(X, GTYPE_SECURITY_UNIVERSAL_GROUP)

            T = T.union(X)

        T.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroupsGlobalAndUniversal"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroupsGlobalAndUniversal']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                         attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(T.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: %s" % T.difference(tokenGroupsSet))

        if len(tokenGroupsSet.difference(T)):
            self.fail(msg="additional tokenGroupsGlobalAndUniversal: %s" % tokenGroupsSet.difference(T))

    def test_samr_GetGroupsForUser(self):
        # Confirm that we get the correct results against SAMR also
        if not url.startswith("ldap://"):
            self.fail(msg="This test is only valid on ldap (so we an find the hostname and use SAMR)")
        host = url.split("://")[1]
        (domain_sid, user_rid) = self.user_sid.split()
        samr_conn = samba.dcerpc.samr.samr("ncacn_ip_tcp:%s[seal]" % host, lp, creds)
        samr_handle = samr_conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
        samr_domain = samr_conn.OpenDomain(samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED,
                                      domain_sid)
        user_handle = samr_conn.OpenUser(samr_domain, security.SEC_FLAG_MAXIMUM_ALLOWED, user_rid)
        rids = samr_conn.GetGroupsForUser(user_handle)
        samr_dns = set()
        for rid in rids.rids:
            self.assertEqual(rid.attributes, samr.SE_GROUP_MANDATORY | samr.SE_GROUP_ENABLED_BY_DEFAULT| samr.SE_GROUP_ENABLED)
            sid = "%s-%d" % (domain_sid, rid.rid)
            res = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                  attrs=[])
            samr_dns.add(res[0].dn.get_casefold())

        user_info = samr_conn.QueryUserInfo(user_handle, 1)
        self.assertEqual(rids.rids[0].rid, user_info.primary_gid)

        tokenGroupsSet = set()
        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroupsGlobalAndUniversal"])
        for sid in res[0]['tokenGroupsGlobalAndUniversal']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                         attrs=[],
                                         expression="(&(|(grouptype=%d)(grouptype=%d))(objectclass=group))"
                                         % (GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP))
            if len(res) == 1:
                tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(samr_dns.difference(tokenGroupsSet)):
            self.fail(msg="additional samr_GetUserGroups over tokenGroups: %s" % samr_dns.difference(tokenGroupsSet))

        memberOf = set()
        # Add the primary group
        primary_group_sid = "%s-%d" % (domain_sid, user_info.primary_gid)
        res2 = self.admin_ldb.search(base="<SID=%s>" % sid, scope=ldb.SCOPE_BASE,
                                     attrs=[])

        memberOf.add(res2[0].dn.get_casefold())
        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["memberOf"])
        for dn in res[0]['memberOf']:
            res3 = self.admin_ldb.search(base=dn, scope=ldb.SCOPE_BASE,
                                         attrs=[],
                                         expression="(&(|(grouptype=%d)(grouptype=%d))(objectclass=group))"
                                         % (GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP))
            if len(res3) == 1:
                memberOf.add(res3[0].dn.get_casefold())

        if len(memberOf.difference(samr_dns)):
            self.fail(msg="additional memberOf over samr_GetUserGroups: %s" % memberOf.difference(samr_dns))

        if len(samr_dns.difference(memberOf)):
            self.fail(msg="additional samr_GetUserGroups over memberOf: %s" % samr_dns.difference(memberOf))

        S = set()
        S.add(self.test_user_dn.get_casefold())

        self.filtered_closure(S, GTYPE_SECURITY_GLOBAL_GROUP)
        self.filtered_closure(S, GTYPE_SECURITY_UNIVERSAL_GROUP)

        # Now remove the user DN and primary group
        S.remove(self.test_user_dn.get_casefold())

        if len(samr_dns.difference(S)):
            self.fail(msg="additional samr_GetUserGroups over filtered_closure: %s" % samr_dns.difference(S))

    def test_samr_GetGroupsForUser_nomember(self):
        # Confirm that we get the correct results against SAMR also
        if not url.startswith("ldap://"):
            self.fail(msg="This test is only valid on ldap (so we an find the hostname and use SAMR)")
        host = url.split("://")[1]

        test_user = "******"
        self.admin_ldb.newuser(test_user, self.test_user_pass)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" % (test_user, self.base_dn),
                                    attrs=["objectSid"], scope=ldb.SCOPE_BASE)
        user_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        (domain_sid, user_rid) = user_sid.split()
        samr_conn = samba.dcerpc.samr.samr("ncacn_ip_tcp:%s[seal]" % host, lp, creds)
        samr_handle = samr_conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
        samr_domain = samr_conn.OpenDomain(samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED,
                                           domain_sid)
        user_handle = samr_conn.OpenUser(samr_domain, security.SEC_FLAG_MAXIMUM_ALLOWED, user_rid)
        rids = samr_conn.GetGroupsForUser(user_handle)
        user_info = samr_conn.QueryUserInfo(user_handle, 1)
        delete_force(self.admin_ldb, "CN=%s,%s,%s" %
                          (test_user, "cn=users", self.base_dn))
        self.assertEqual(len(rids.rids), 1)
        self.assertEqual(rids.rids[0].rid, user_info.primary_gid)
예제 #10
0
class GroupAuditTests(AuditLogTestBase):

    def setUp(self):
        self.message_type = MSG_GROUP_LOG
        self.event_type   = DSDB_GROUP_EVENT_NAME
        super(GroupAuditTests, self).setUp()

        self.remoteAddress = os.environ["CLIENT_IP"]
        self.server_ip = os.environ["SERVER_IP"]

        host = "ldap://%s" % os.environ["SERVER"]
        self.ldb = SamDB(url=host,
                         session_info=system_session(),
                         credentials=self.get_credentials(),
                         lp=self.get_loadparm())
        self.server = os.environ["SERVER"]

        # Gets back the basedn
        self.base_dn = self.ldb.domain_dn()

        # Get the old "dSHeuristics" if it was set
        dsheuristics = self.ldb.get_dsheuristics()

        # Set the "dSHeuristics" to activate the correct "userPassword"
        # behaviour
        self.ldb.set_dsheuristics("000000001")

        # Reset the "dSHeuristics" as they were before
        self.addCleanup(self.ldb.set_dsheuristics, dsheuristics)

        # Get the old "minPwdAge"
        minPwdAge = self.ldb.get_minPwdAge()

        # Set it temporarily to "0"
        self.ldb.set_minPwdAge("0")
        self.base_dn = self.ldb.domain_dn()

        # Reset the "minPwdAge" as it was before
        self.addCleanup(self.ldb.set_minPwdAge, minPwdAge)

        # (Re)adds the test user USER_NAME with password USER_PASS
        self.ldb.add({
            "dn": "cn=" + USER_NAME + ",cn=users," + self.base_dn,
            "objectclass": "user",
            "sAMAccountName": USER_NAME,
            "userPassword": USER_PASS
        })
        self.ldb.newgroup(GROUP_NAME_01)
        self.ldb.newgroup(GROUP_NAME_02)

    def tearDown(self):
        super(GroupAuditTests, self).tearDown()
        delete_force(self.ldb, "cn=" + USER_NAME + ",cn=users," + self.base_dn)
        self.ldb.deletegroup(GROUP_NAME_01)
        self.ldb.deletegroup(GROUP_NAME_02)

    def test_add_and_remove_users_from_group(self):

        #
        # Wait for the primary group change for the created user.
        #
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("PrimaryGroup", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Add the user to a group
        #
        self.discardMessages()

        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME])
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Add the user to another group
        #
        self.discardMessages()
        self.ldb.add_remove_group_members(GROUP_NAME_02, [USER_NAME])

        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_02 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Remove the user from a group
        #
        self.discardMessages()
        self.ldb.add_remove_group_members(
            GROUP_NAME_01,
            [USER_NAME],
            add_members_operation=False)
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Removed", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Re-add the user to a group
        #
        self.discardMessages()
        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME])

        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

    def test_change_primary_group(self):

        #
        # Wait for the primary group change for the created user.
        #
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("PrimaryGroup", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Add the user to a group, the user needs to be a member of a group
        # before there primary group can be set to that group.
        #
        self.discardMessages()

        self.ldb.add_remove_group_members(GROUP_NAME_01, [USER_NAME])
        messages = self.waitForMessages(1)
        print("Received %d messages" % len(messages))
        self.assertEquals(1,
                          len(messages),
                          "Did not receive the expected number of messages")
        audit = messages[0]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        #
        # Change the primary group of a user
        #
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        # get the primaryGroupToken of the group
        res = self.ldb.search(base=group_dn, attrs=["primaryGroupToken"],
                              scope=ldb.SCOPE_BASE)
        group_id = res[0]["primaryGroupToken"]

        # set primaryGroupID attribute of the user to that group
        m = ldb.Message()
        m.dn = ldb.Dn(self.ldb, user_dn)
        m["primaryGroupID"] = ldb.MessageElement(
            group_id,
            FLAG_MOD_REPLACE,
            "primaryGroupID")
        self.discardMessages()
        self.ldb.modify(m)

        #
        # Wait for the primary group change.
        # Will see the user removed from the new group
        #          the user added to their old primary group
        #          and a new primary group event.
        #
        messages = self.waitForMessages(3)
        print("Received %d messages" % len(messages))
        self.assertEquals(3,
                          len(messages),
                          "Did not receive the expected number of messages")

        audit = messages[0]["groupChange"]
        self.assertEqual("Removed", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        audit = messages[1]["groupChange"]

        self.assertEqual("Added", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=domain users,cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")

        audit = messages[2]["groupChange"]

        self.assertEqual("PrimaryGroup", audit["action"])
        user_dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
        group_dn = "cn=" + GROUP_NAME_01 + ",cn=users," + self.base_dn
        self.assertTrue(user_dn.lower(), audit["user"].lower())
        self.assertTrue(group_dn.lower(), audit["group"].lower())
        self.assertRegexpMatches(audit["remoteAddress"],
                                 self.remoteAddress)
        self.assertTrue(self.is_guid(audit["sessionId"]))
        session_id = self.get_session()
        self.assertEquals(session_id, audit["sessionId"])
        service_description = self.get_service_description()
        self.assertEquals(service_description, "LDAP")
예제 #11
0
class DynamicTokenTest(samba.tests.TestCase):
    def get_creds(self, target_username, target_password):
        creds_tmp = Credentials()
        creds_tmp.set_username(target_username)
        creds_tmp.set_password(target_password)
        creds_tmp.set_domain(creds.get_domain())
        creds_tmp.set_realm(creds.get_realm())
        creds_tmp.set_workstation(creds.get_workstation())
        creds_tmp.set_gensec_features(creds_tmp.get_gensec_features()
                                      | gensec.FEATURE_SEAL)
        return creds_tmp

    def get_ldb_connection(self, target_username, target_password):
        creds_tmp = self.get_creds(target_username, target_password)
        ldb_target = SamDB(url=url, credentials=creds_tmp, lp=lp)
        return ldb_target

    def setUp(self):
        super(DynamicTokenTest, self).setUp()
        self.admin_ldb = SamDB(url,
                               credentials=creds,
                               session_info=system_session(lp),
                               lp=lp)

        self.base_dn = self.admin_ldb.domain_dn()

        self.test_user = "******"
        self.test_user_pass = "******"
        self.admin_ldb.newuser(self.test_user, self.test_user_pass)
        self.test_group0 = "tokengroups_group0"
        self.admin_ldb.newgroup(
            self.test_group0, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group0, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group0_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group0,
                                                [self.test_user],
                                                add_members_operation=True)

        self.test_group1 = "tokengroups_group1"
        self.admin_ldb.newgroup(self.test_group1,
                                grouptype=dsdb.GTYPE_SECURITY_GLOBAL_GROUP)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group1, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group1_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group1,
                                                [self.test_user],
                                                add_members_operation=True)

        self.test_group2 = "tokengroups_group2"
        self.admin_ldb.newgroup(self.test_group2,
                                grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group2, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group2_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group2,
                                                [self.test_user],
                                                add_members_operation=True)

        self.ldb = self.get_ldb_connection(self.test_user, self.test_user_pass)

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        self.user_sid_dn = "<SID=%s>" % str(
            ndr_unpack(samba.dcerpc.security.dom_sid,
                       res[0]["tokenGroups"][0]))

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=[])
        self.assertEquals(len(res), 1)

        self.test_user_dn = res[0].dn

        session_info_flags = (AUTH_SESSION_INFO_DEFAULT_GROUPS
                              | AUTH_SESSION_INFO_AUTHENTICATED
                              | AUTH_SESSION_INFO_SIMPLE_PRIVILEGES)
        session = samba.auth.user_session(
            self.ldb,
            lp_ctx=lp,
            dn=self.user_sid_dn,
            session_info_flags=session_info_flags)

        token = session.security_token
        self.user_sids = []
        for s in token.sids:
            self.user_sids.append(str(s))

    def tearDown(self):
        super(DynamicTokenTest, self).tearDown()
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_user, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group0, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group1, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group2, "cn=users", self.base_dn))

    def test_rootDSE_tokenGroups(self):
        """Testing rootDSE tokengroups against internal calculation"""
        if not url.startswith("ldap"):
            self.fail(msg="This test is only valid on ldap")

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        print("Getting tokenGroups from rootDSE")
        tokengroups = []
        for sid in res[0]['tokenGroups']:
            tokengroups.append(
                str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("tokengroups: %s" % tokengroups)
            print("calculated : %s" % self.user_sids)
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(
                msg="calculated groups don't match against rootDSE tokenGroups"
            )

    def test_dn_tokenGroups(self):
        print("Getting tokenGroups from user DN")
        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroups']:
            dn_tokengroups.append(
                str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(dn_tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(
                msg="calculated groups don't match against user DN tokenGroups"
            )

    def test_pac_groups(self):
        settings = {}
        settings["lp_ctx"] = lp
        settings["target_hostname"] = lp.get("netbios name")

        gensec_client = gensec.Security.start_client(settings)
        gensec_client.set_credentials(
            self.get_creds(self.test_user, self.test_user_pass))
        gensec_client.want_feature(gensec.FEATURE_SEAL)
        gensec_client.start_mech_by_sasl_name("GSSAPI")

        auth_context = AuthContext(lp_ctx=lp, ldb=self.ldb, methods=[])

        gensec_server = gensec.Security.start_server(settings, auth_context)
        machine_creds = Credentials()
        machine_creds.guess(lp)
        machine_creds.set_machine_account(lp)
        gensec_server.set_credentials(machine_creds)

        gensec_server.want_feature(gensec.FEATURE_SEAL)
        gensec_server.start_mech_by_sasl_name("GSSAPI")

        client_finished = False
        server_finished = False
        server_to_client = ""

        # Run the actual call loop.
        while client_finished == False and server_finished == False:
            if not client_finished:
                print "running client gensec_update"
                (client_finished,
                 client_to_server) = gensec_client.update(server_to_client)
            if not server_finished:
                print "running server gensec_update"
                (server_finished,
                 server_to_client) = gensec_server.update(client_to_server)

        session = gensec_server.session_info()

        token = session.security_token
        pac_sids = []
        for s in token.sids:
            pac_sids.append(str(s))

        sidset1 = set(pac_sids)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(
                msg="calculated groups don't match against user PAC tokenGroups"
            )

    def test_tokenGroups_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result
        res = self.admin_ldb.search(
            base=self.base_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="(|(objectclass=user)(objectclass=group))",
            attrs=["memberOf"])
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(base=self.base_dn,
                                    scope=ldb.SCOPE_SUBTREE,
                                    expression="(objectclass=user)",
                                    attrs=["primaryGroupID"])
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "%s-%d" % (self.admin_ldb.get_domain_sid(),
                                 int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                             scope=ldb.SCOPE_BASE,
                                             attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        wSet = set()
        wSet.add(self.test_user_dn.get_casefold())
        closure(vSet, wSet, aSet)
        wSet.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroups']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                         scope=ldb.SCOPE_BASE,
                                         attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(wSet.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: %s" %
                      wSet.difference(tokenGroupsSet))

        if len(tokenGroupsSet.difference(wSet)):
            self.fail(msg="additional tokenGroups: %s" %
                      tokenGroupsSet.difference(wSet))

    def filtered_closure(self, wSet, filter_grouptype):
        res = self.admin_ldb.search(
            base=self.base_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="(|(objectclass=user)(objectclass=group))",
            attrs=["memberOf"])
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            vSet.add(obj.dn.get_casefold())
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(base=self.base_dn,
                                    scope=ldb.SCOPE_SUBTREE,
                                    expression="(objectclass=user)",
                                    attrs=["primaryGroupID"])
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "%s-%d" % (self.admin_ldb.get_domain_sid(),
                                 int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                             scope=ldb.SCOPE_BASE,
                                             attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        uSet = set()
        for v in vSet:
            res_group = self.admin_ldb.search(base=v,
                                              scope=ldb.SCOPE_BASE,
                                              attrs=["groupType"],
                                              expression="objectClass=group")
            if len(res_group) == 1:
                if hex(int(res_group[0]["groupType"][0])
                       & 0x00000000FFFFFFFF) == hex(filter_grouptype):
                    uSet.add(v)
            else:
                uSet.add(v)

        closure(uSet, wSet, aSet)

    def test_tokenGroupsGlobalAndUniversal_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result

        # The variable names come from MS-ADTS May 15, 2014

        S = set()
        S.add(self.test_user_dn.get_casefold())

        self.filtered_closure(S, GTYPE_SECURITY_GLOBAL_GROUP)

        T = set()
        # Not really a SID, we do this on DNs...
        for sid in S:
            X = set()
            X.add(sid)
            self.filtered_closure(X, GTYPE_SECURITY_UNIVERSAL_GROUP)

            T = T.union(X)

        T.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroupsGlobalAndUniversal"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroupsGlobalAndUniversal']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                         scope=ldb.SCOPE_BASE,
                                         attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(T.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: %s" %
                      T.difference(tokenGroupsSet))

        if len(tokenGroupsSet.difference(T)):
            self.fail(msg="additional tokenGroupsGlobalAndUniversal: %s" %
                      tokenGroupsSet.difference(T))
예제 #12
0
class DynamicTokenTest(samba.tests.TestCase):
    def get_creds(self, target_username, target_password):
        creds_tmp = Credentials()
        creds_tmp.set_username(target_username)
        creds_tmp.set_password(target_password)
        creds_tmp.set_domain(creds.get_domain())
        creds_tmp.set_realm(creds.get_realm())
        creds_tmp.set_workstation(creds.get_workstation())
        creds_tmp.set_gensec_features(creds_tmp.get_gensec_features()
                                      | gensec.FEATURE_SEAL)
        return creds_tmp

    def get_ldb_connection(self, target_username, target_password):
        creds_tmp = self.get_creds(target_username, target_password)
        ldb_target = SamDB(url=url, credentials=creds_tmp, lp=lp)
        return ldb_target

    def setUp(self):
        super(DynamicTokenTest, self).setUp()
        self.admin_ldb = SamDB(url,
                               credentials=creds,
                               session_info=system_session(lp),
                               lp=lp)

        self.base_dn = self.admin_ldb.domain_dn()

        self.test_user = "******"
        self.test_user_pass = "******"
        self.admin_ldb.newuser(self.test_user, self.test_user_pass)
        self.test_group0 = "tokengroups_group0"
        self.admin_ldb.newgroup(
            self.test_group0, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group0, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group0_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group0,
                                                [self.test_user],
                                                add_members_operation=True)

        self.test_group1 = "tokengroups_group1"
        self.admin_ldb.newgroup(self.test_group1,
                                grouptype=dsdb.GTYPE_SECURITY_GLOBAL_GROUP)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group1, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group1_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group1,
                                                [self.test_user],
                                                add_members_operation=True)

        self.test_group2 = "tokengroups_group2"
        self.admin_ldb.newgroup(self.test_group2,
                                grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group2, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group2_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group2,
                                                [self.test_user],
                                                add_members_operation=True)

        self.test_group3 = "tokengroups_group3"
        self.admin_ldb.newgroup(self.test_group3,
                                grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group3, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group3_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group3,
                                                [self.test_group1],
                                                add_members_operation=True)

        self.test_group4 = "tokengroups_group4"
        self.admin_ldb.newgroup(self.test_group4,
                                grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group4, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group4_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group4,
                                                [self.test_group3],
                                                add_members_operation=True)

        self.test_group5 = "tokengroups_group5"
        self.admin_ldb.newgroup(
            self.test_group5, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group5, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group5_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group5,
                                                [self.test_group4],
                                                add_members_operation=True)

        self.test_group6 = "tokengroups_group6"
        self.admin_ldb.newgroup(
            self.test_group6, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)

        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (self.test_group6, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        self.test_group6_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                          res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group6,
                                                [self.test_user],
                                                add_members_operation=True)

        self.ldb = self.get_ldb_connection(self.test_user, self.test_user_pass)

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        self.user_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                                   res[0]["tokenGroups"][0])
        self.user_sid_dn = "<SID=%s>" % str(self.user_sid)

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=[])
        self.assertEquals(len(res), 1)

        self.test_user_dn = res[0].dn

        session_info_flags = (AUTH_SESSION_INFO_DEFAULT_GROUPS
                              | AUTH_SESSION_INFO_AUTHENTICATED
                              | AUTH_SESSION_INFO_SIMPLE_PRIVILEGES)

        if creds.get_kerberos_state() == DONT_USE_KERBEROS:
            session_info_flags |= AUTH_SESSION_INFO_NTLM

        session = samba.auth.user_session(
            self.ldb,
            lp_ctx=lp,
            dn=self.user_sid_dn,
            session_info_flags=session_info_flags)

        token = session.security_token
        self.user_sids = []
        for s in token.sids:
            self.user_sids.append(str(s))

    def tearDown(self):
        super(DynamicTokenTest, self).tearDown()
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_user, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group0, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group1, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group2, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group3, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group4, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group5, "cn=users", self.base_dn))
        delete_force(
            self.admin_ldb,
            "CN=%s,%s,%s" % (self.test_group6, "cn=users", self.base_dn))

    def test_rootDSE_tokenGroups(self):
        """Testing rootDSE tokengroups against internal calculation"""
        if not url.startswith("ldap"):
            self.fail(msg="This test is only valid on ldap")

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        print("Getting tokenGroups from rootDSE")
        tokengroups = []
        for sid in res[0]['tokenGroups']:
            tokengroups.append(
                str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("tokengroups: %s" % tokengroups)
            print("calculated : %s" % self.user_sids)
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(
                msg="calculated groups don't match against rootDSE tokenGroups"
            )

    def test_dn_tokenGroups(self):
        print("Getting tokenGroups from user DN")
        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroups']:
            dn_tokengroups.append(
                str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(dn_tokengroups)
        sidset2 = set(self.user_sids)

        # The SIDs on the DN do not include the NTLM authentication SID
        sidset2.discard(samba.dcerpc.security.SID_NT_NTLM_AUTHENTICATION)

        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(
                msg="calculated groups don't match against user DN tokenGroups"
            )

    def test_pac_groups(self):
        settings = {}
        settings["lp_ctx"] = lp
        settings["target_hostname"] = lp.get("netbios name")

        gensec_client = gensec.Security.start_client(settings)
        gensec_client.set_credentials(
            self.get_creds(self.test_user, self.test_user_pass))
        gensec_client.want_feature(gensec.FEATURE_SEAL)
        gensec_client.start_mech_by_sasl_name("GSSAPI")

        auth_context = AuthContext(lp_ctx=lp, ldb=self.ldb, methods=[])

        gensec_server = gensec.Security.start_server(settings, auth_context)
        machine_creds = Credentials()
        machine_creds.guess(lp)
        machine_creds.set_machine_account(lp)
        gensec_server.set_credentials(machine_creds)

        gensec_server.want_feature(gensec.FEATURE_SEAL)
        gensec_server.start_mech_by_sasl_name("GSSAPI")

        client_finished = False
        server_finished = False
        server_to_client = ""

        # Run the actual call loop.
        while client_finished == False and server_finished == False:
            if not client_finished:
                print "running client gensec_update"
                (client_finished,
                 client_to_server) = gensec_client.update(server_to_client)
            if not server_finished:
                print "running server gensec_update"
                (server_finished,
                 server_to_client) = gensec_server.update(client_to_server)

        session = gensec_server.session_info()

        token = session.security_token
        pac_sids = []
        for s in token.sids:
            pac_sids.append(str(s))

        sidset1 = set(pac_sids)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print("token sids don't match")
            print("difference : %s" % sidset1.difference(sidset2))
            self.fail(
                msg="calculated groups don't match against user PAC tokenGroups"
            )

    def test_tokenGroups_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result
        res = self.admin_ldb.search(
            base=self.base_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="(|(objectclass=user)(objectclass=group))",
            attrs=["memberOf"])
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(base=self.base_dn,
                                    scope=ldb.SCOPE_SUBTREE,
                                    expression="(objectclass=user)",
                                    attrs=["primaryGroupID"])
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "%s-%d" % (self.admin_ldb.get_domain_sid(),
                                 int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                             scope=ldb.SCOPE_BASE,
                                             attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        wSet = set()
        wSet.add(self.test_user_dn.get_casefold())
        closure(vSet, wSet, aSet)
        wSet.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroups']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                         scope=ldb.SCOPE_BASE,
                                         attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(wSet.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: %s" %
                      wSet.difference(tokenGroupsSet))

        if len(tokenGroupsSet.difference(wSet)):
            self.fail(msg="additional tokenGroups: %s" %
                      tokenGroupsSet.difference(wSet))

    def filtered_closure(self, wSet, filter_grouptype):
        res = self.admin_ldb.search(
            base=self.base_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="(|(objectclass=user)(objectclass=group))",
            attrs=["memberOf"])
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            vSet.add(obj.dn.get_casefold())
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(base=self.base_dn,
                                    scope=ldb.SCOPE_SUBTREE,
                                    expression="(objectclass=user)",
                                    attrs=["primaryGroupID"])
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "%s-%d" % (self.admin_ldb.get_domain_sid(),
                                 int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                             scope=ldb.SCOPE_BASE,
                                             attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        uSet = set()
        for v in vSet:
            res_group = self.admin_ldb.search(base=v,
                                              scope=ldb.SCOPE_BASE,
                                              attrs=["groupType"],
                                              expression="objectClass=group")
            if len(res_group) == 1:
                if hex(int(res_group[0]["groupType"][0])
                       & 0x00000000FFFFFFFF) == hex(filter_grouptype):
                    uSet.add(v)
            else:
                uSet.add(v)

        closure(uSet, wSet, aSet)

    def test_tokenGroupsGlobalAndUniversal_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result

        # The variable names come from MS-ADTS May 15, 2014

        S = set()
        S.add(self.test_user_dn.get_casefold())

        self.filtered_closure(S, GTYPE_SECURITY_GLOBAL_GROUP)

        T = set()
        # Not really a SID, we do this on DNs...
        for sid in S:
            X = set()
            X.add(sid)
            self.filtered_closure(X, GTYPE_SECURITY_UNIVERSAL_GROUP)

            T = T.union(X)

        T.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroupsGlobalAndUniversal"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]['tokenGroupsGlobalAndUniversal']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                         scope=ldb.SCOPE_BASE,
                                         attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(T.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: %s" %
                      T.difference(tokenGroupsSet))

        if len(tokenGroupsSet.difference(T)):
            self.fail(msg="additional tokenGroupsGlobalAndUniversal: %s" %
                      tokenGroupsSet.difference(T))

    def test_samr_GetGroupsForUser(self):
        # Confirm that we get the correct results against SAMR also
        if not url.startswith("ldap://"):
            self.fail(
                msg=
                "This test is only valid on ldap (so we an find the hostname and use SAMR)"
            )
        host = url.split("://")[1]
        (domain_sid, user_rid) = self.user_sid.split()
        samr_conn = samba.dcerpc.samr.samr("ncacn_ip_tcp:%s[seal]" % host, lp,
                                           creds)
        samr_handle = samr_conn.Connect2(None,
                                         security.SEC_FLAG_MAXIMUM_ALLOWED)
        samr_domain = samr_conn.OpenDomain(samr_handle,
                                           security.SEC_FLAG_MAXIMUM_ALLOWED,
                                           domain_sid)
        user_handle = samr_conn.OpenUser(samr_domain,
                                         security.SEC_FLAG_MAXIMUM_ALLOWED,
                                         user_rid)
        rids = samr_conn.GetGroupsForUser(user_handle)
        samr_dns = set()
        for rid in rids.rids:
            self.assertEqual(
                rid.attributes, samr.SE_GROUP_MANDATORY
                | samr.SE_GROUP_ENABLED_BY_DEFAULT | samr.SE_GROUP_ENABLED)
            sid = "%s-%d" % (domain_sid, rid.rid)
            res = self.admin_ldb.search(base="<SID=%s>" % sid,
                                        scope=ldb.SCOPE_BASE,
                                        attrs=[])
            samr_dns.add(res[0].dn.get_casefold())

        user_info = samr_conn.QueryUserInfo(user_handle, 1)
        self.assertEqual(rids.rids[0].rid, user_info.primary_gid)

        tokenGroupsSet = set()
        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["tokenGroupsGlobalAndUniversal"])
        for sid in res[0]['tokenGroupsGlobalAndUniversal']:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(
                base="<SID=%s>" % sid,
                scope=ldb.SCOPE_BASE,
                attrs=[],
                expression=
                "(&(|(grouptype=%d)(grouptype=%d))(objectclass=group))" %
                (GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP))
            if len(res) == 1:
                tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(samr_dns.difference(tokenGroupsSet)):
            self.fail(
                msg="additional samr_GetUserGroups over tokenGroups: %s" %
                samr_dns.difference(tokenGroupsSet))

        memberOf = set()
        # Add the primary group
        primary_group_sid = "%s-%d" % (domain_sid, user_info.primary_gid)
        res2 = self.admin_ldb.search(base="<SID=%s>" % sid,
                                     scope=ldb.SCOPE_BASE,
                                     attrs=[])

        memberOf.add(res2[0].dn.get_casefold())
        res = self.ldb.search(self.user_sid_dn,
                              scope=ldb.SCOPE_BASE,
                              attrs=["memberOf"])
        for dn in res[0]['memberOf']:
            res3 = self.admin_ldb.search(
                base=dn,
                scope=ldb.SCOPE_BASE,
                attrs=[],
                expression=
                "(&(|(grouptype=%d)(grouptype=%d))(objectclass=group))" %
                (GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP))
            if len(res3) == 1:
                memberOf.add(res3[0].dn.get_casefold())

        if len(memberOf.difference(samr_dns)):
            self.fail(msg="additional memberOf over samr_GetUserGroups: %s" %
                      memberOf.difference(samr_dns))

        if len(samr_dns.difference(memberOf)):
            self.fail(msg="additional samr_GetUserGroups over memberOf: %s" %
                      samr_dns.difference(memberOf))

        S = set()
        S.add(self.test_user_dn.get_casefold())

        self.filtered_closure(S, GTYPE_SECURITY_GLOBAL_GROUP)
        self.filtered_closure(S, GTYPE_SECURITY_UNIVERSAL_GROUP)

        # Now remove the user DN and primary group
        S.remove(self.test_user_dn.get_casefold())

        if len(samr_dns.difference(S)):
            self.fail(
                msg="additional samr_GetUserGroups over filtered_closure: %s" %
                samr_dns.difference(S))

    def test_samr_GetGroupsForUser_nomember(self):
        # Confirm that we get the correct results against SAMR also
        if not url.startswith("ldap://"):
            self.fail(
                msg=
                "This test is only valid on ldap (so we an find the hostname and use SAMR)"
            )
        host = url.split("://")[1]

        test_user = "******"
        self.admin_ldb.newuser(test_user, self.test_user_pass)
        res = self.admin_ldb.search(base="cn=%s,cn=users,%s" %
                                    (test_user, self.base_dn),
                                    attrs=["objectSid"],
                                    scope=ldb.SCOPE_BASE)
        user_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
                              res[0]["objectSid"][0])

        (domain_sid, user_rid) = user_sid.split()
        samr_conn = samba.dcerpc.samr.samr("ncacn_ip_tcp:%s[seal]" % host, lp,
                                           creds)
        samr_handle = samr_conn.Connect2(None,
                                         security.SEC_FLAG_MAXIMUM_ALLOWED)
        samr_domain = samr_conn.OpenDomain(samr_handle,
                                           security.SEC_FLAG_MAXIMUM_ALLOWED,
                                           domain_sid)
        user_handle = samr_conn.OpenUser(samr_domain,
                                         security.SEC_FLAG_MAXIMUM_ALLOWED,
                                         user_rid)
        rids = samr_conn.GetGroupsForUser(user_handle)
        user_info = samr_conn.QueryUserInfo(user_handle, 1)
        delete_force(self.admin_ldb,
                     "CN=%s,%s,%s" % (test_user, "cn=users", self.base_dn))
        self.assertEqual(len(rids.rids), 1)
        self.assertEqual(rids.rids[0].rid, user_info.primary_gid)
예제 #13
0
파일: token_group.py 프로젝트: runt18/samba
class DynamicTokenTest(samba.tests.TestCase):
    def get_creds(self, target_username, target_password):
        creds_tmp = Credentials()
        creds_tmp.set_username(target_username)
        creds_tmp.set_password(target_password)
        creds_tmp.set_domain(creds.get_domain())
        creds_tmp.set_realm(creds.get_realm())
        creds_tmp.set_workstation(creds.get_workstation())
        creds_tmp.set_gensec_features(creds_tmp.get_gensec_features() | gensec.FEATURE_SEAL)
        return creds_tmp

    def get_ldb_connection(self, target_username, target_password):
        creds_tmp = self.get_creds(target_username, target_password)
        ldb_target = SamDB(url=url, credentials=creds_tmp, lp=lp)
        return ldb_target

    def setUp(self):
        super(DynamicTokenTest, self).setUp()
        self.admin_ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp)

        self.base_dn = self.admin_ldb.domain_dn()

        self.test_user = "******"
        self.test_user_pass = "******"
        self.admin_ldb.newuser(self.test_user, self.test_user_pass)
        self.test_group0 = "tokengroups_group0"
        self.admin_ldb.newgroup(self.test_group0, grouptype=dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)
        res = self.admin_ldb.search(
            base="cn={0!s},cn=users,{1!s}".format(self.test_group0, self.base_dn),
            attrs=["objectSid"],
            scope=ldb.SCOPE_BASE,
        )
        self.test_group0_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group0, [self.test_user], add_members_operation=True)

        self.test_group1 = "tokengroups_group1"
        self.admin_ldb.newgroup(self.test_group1, grouptype=dsdb.GTYPE_SECURITY_GLOBAL_GROUP)
        res = self.admin_ldb.search(
            base="cn={0!s},cn=users,{1!s}".format(self.test_group1, self.base_dn),
            attrs=["objectSid"],
            scope=ldb.SCOPE_BASE,
        )
        self.test_group1_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group1, [self.test_user], add_members_operation=True)

        self.test_group2 = "tokengroups_group2"
        self.admin_ldb.newgroup(self.test_group2, grouptype=dsdb.GTYPE_SECURITY_UNIVERSAL_GROUP)

        res = self.admin_ldb.search(
            base="cn={0!s},cn=users,{1!s}".format(self.test_group2, self.base_dn),
            attrs=["objectSid"],
            scope=ldb.SCOPE_BASE,
        )
        self.test_group2_sid = ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["objectSid"][0])

        self.admin_ldb.add_remove_group_members(self.test_group2, [self.test_user], add_members_operation=True)

        self.ldb = self.get_ldb_connection(self.test_user, self.test_user_pass)

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        self.user_sid_dn = "<SID={0!s}>".format(
            str(ndr_unpack(samba.dcerpc.security.dom_sid, res[0]["tokenGroups"][0]))
        )

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=[])
        self.assertEquals(len(res), 1)

        self.test_user_dn = res[0].dn

        session_info_flags = (
            AUTH_SESSION_INFO_DEFAULT_GROUPS | AUTH_SESSION_INFO_AUTHENTICATED | AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
        )
        session = samba.auth.user_session(
            self.ldb, lp_ctx=lp, dn=self.user_sid_dn, session_info_flags=session_info_flags
        )

        token = session.security_token
        self.user_sids = []
        for s in token.sids:
            self.user_sids.append(str(s))

    def tearDown(self):
        super(DynamicTokenTest, self).tearDown()
        delete_force(self.admin_ldb, "CN={0!s},{1!s},{2!s}".format(self.test_user, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN={0!s},{1!s},{2!s}".format(self.test_group0, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN={0!s},{1!s},{2!s}".format(self.test_group1, "cn=users", self.base_dn))
        delete_force(self.admin_ldb, "CN={0!s},{1!s},{2!s}".format(self.test_group2, "cn=users", self.base_dn))

    def test_rootDSE_tokenGroups(self):
        """Testing rootDSE tokengroups against internal calculation"""
        if not url.startswith("ldap"):
            self.fail(msg="This test is only valid on ldap")

        res = self.ldb.search("", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        print ("Getting tokenGroups from rootDSE")
        tokengroups = []
        for sid in res[0]["tokenGroups"]:
            tokengroups.append(str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print ("token sids don't match")
            print ("tokengroups: {0!s}".format(tokengroups))
            print ("calculated : {0!s}".format(self.user_sids))
            print ("difference : {0!s}".format(sidset1.difference(sidset2)))
            self.fail(msg="calculated groups don't match against rootDSE tokenGroups")

    def test_dn_tokenGroups(self):
        print ("Getting tokenGroups from user DN")
        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]["tokenGroups"]:
            dn_tokengroups.append(str(ndr_unpack(samba.dcerpc.security.dom_sid, sid)))

        sidset1 = set(dn_tokengroups)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print ("token sids don't match")
            print ("difference : {0!s}".format(sidset1.difference(sidset2)))
            self.fail(msg="calculated groups don't match against user DN tokenGroups")

    def test_pac_groups(self):
        settings = {}
        settings["lp_ctx"] = lp
        settings["target_hostname"] = lp.get("netbios name")

        gensec_client = gensec.Security.start_client(settings)
        gensec_client.set_credentials(self.get_creds(self.test_user, self.test_user_pass))
        gensec_client.want_feature(gensec.FEATURE_SEAL)
        gensec_client.start_mech_by_sasl_name("GSSAPI")

        auth_context = AuthContext(lp_ctx=lp, ldb=self.ldb, methods=[])

        gensec_server = gensec.Security.start_server(settings, auth_context)
        machine_creds = Credentials()
        machine_creds.guess(lp)
        machine_creds.set_machine_account(lp)
        gensec_server.set_credentials(machine_creds)

        gensec_server.want_feature(gensec.FEATURE_SEAL)
        gensec_server.start_mech_by_sasl_name("GSSAPI")

        client_finished = False
        server_finished = False
        server_to_client = ""

        # Run the actual call loop.
        while client_finished == False and server_finished == False:
            if not client_finished:
                print "running client gensec_update"
                (client_finished, client_to_server) = gensec_client.update(server_to_client)
            if not server_finished:
                print "running server gensec_update"
                (server_finished, server_to_client) = gensec_server.update(client_to_server)

        session = gensec_server.session_info()

        token = session.security_token
        pac_sids = []
        for s in token.sids:
            pac_sids.append(str(s))

        sidset1 = set(pac_sids)
        sidset2 = set(self.user_sids)
        if len(sidset1.difference(sidset2)):
            print ("token sids don't match")
            print ("difference : {0!s}".format(sidset1.difference(sidset2)))
            self.fail(msg="calculated groups don't match against user PAC tokenGroups")

    def test_tokenGroups_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result
        res = self.admin_ldb.search(
            base=self.base_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="(|(objectclass=user)(objectclass=group))",
            attrs=["memberOf"],
        )
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(
            base=self.base_dn, scope=ldb.SCOPE_SUBTREE, expression="(objectclass=user)", attrs=["primaryGroupID"]
        )
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "{0!s}-{1:d}".format(self.admin_ldb.get_domain_sid(), int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID={0!s}>".format(sid), scope=ldb.SCOPE_BASE, attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        wSet = set()
        wSet.add(self.test_user_dn.get_casefold())
        closure(vSet, wSet, aSet)
        wSet.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]["tokenGroups"]:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID={0!s}>".format(sid), scope=ldb.SCOPE_BASE, attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(wSet.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: {0!s}".format(wSet.difference(tokenGroupsSet)))

        if len(tokenGroupsSet.difference(wSet)):
            self.fail(msg="additional tokenGroups: {0!s}".format(tokenGroupsSet.difference(wSet)))

    def filtered_closure(self, wSet, filter_grouptype):
        res = self.admin_ldb.search(
            base=self.base_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="(|(objectclass=user)(objectclass=group))",
            attrs=["memberOf"],
        )
        aSet = set()
        aSetR = set()
        vSet = set()
        for obj in res:
            vSet.add(obj.dn.get_casefold())
            if "memberOf" in obj:
                for dn in obj["memberOf"]:
                    first = obj.dn.get_casefold()
                    second = ldb.Dn(self.admin_ldb, dn).get_casefold()
                    aSet.add((first, second))
                    aSetR.add((second, first))
                    vSet.add(first)
                    vSet.add(second)

        res = self.admin_ldb.search(
            base=self.base_dn, scope=ldb.SCOPE_SUBTREE, expression="(objectclass=user)", attrs=["primaryGroupID"]
        )
        for obj in res:
            if "primaryGroupID" in obj:
                sid = "{0!s}-{1:d}".format(self.admin_ldb.get_domain_sid(), int(obj["primaryGroupID"][0]))
                res2 = self.admin_ldb.search(base="<SID={0!s}>".format(sid), scope=ldb.SCOPE_BASE, attrs=[])
                first = obj.dn.get_casefold()
                second = res2[0].dn.get_casefold()

                aSet.add((first, second))
                aSetR.add((second, first))
                vSet.add(first)
                vSet.add(second)

        uSet = set()
        for v in vSet:
            res_group = self.admin_ldb.search(
                base=v, scope=ldb.SCOPE_BASE, attrs=["groupType"], expression="objectClass=group"
            )
            if len(res_group) == 1:
                if hex(int(res_group[0]["groupType"][0]) & 0x00000000FFFFFFFF) == hex(filter_grouptype):
                    uSet.add(v)
            else:
                uSet.add(v)

        closure(uSet, wSet, aSet)

    def test_tokenGroupsGlobalAndUniversal_manual(self):
        # Manually run the tokenGroups algorithm from MS-ADTS 3.1.1.4.5.19 and MS-DRSR 4.1.8.3
        # and compare the result

        # The variable names come from MS-ADTS May 15, 2014

        S = set()
        S.add(self.test_user_dn.get_casefold())

        self.filtered_closure(S, GTYPE_SECURITY_GLOBAL_GROUP)

        T = set()
        # Not really a SID, we do this on DNs...
        for sid in S:
            X = set()
            X.add(sid)
            self.filtered_closure(X, GTYPE_SECURITY_UNIVERSAL_GROUP)

            T = T.union(X)

        T.remove(self.test_user_dn.get_casefold())

        tokenGroupsSet = set()

        res = self.ldb.search(self.user_sid_dn, scope=ldb.SCOPE_BASE, attrs=["tokenGroupsGlobalAndUniversal"])
        self.assertEquals(len(res), 1)

        dn_tokengroups = []
        for sid in res[0]["tokenGroupsGlobalAndUniversal"]:
            sid = ndr_unpack(samba.dcerpc.security.dom_sid, sid)
            res3 = self.admin_ldb.search(base="<SID={0!s}>".format(sid), scope=ldb.SCOPE_BASE, attrs=[])
            tokenGroupsSet.add(res3[0].dn.get_casefold())

        if len(T.difference(tokenGroupsSet)):
            self.fail(msg="additional calculated: {0!s}".format(T.difference(tokenGroupsSet)))

        if len(tokenGroupsSet.difference(T)):
            self.fail(msg="additional tokenGroupsGlobalAndUniversal: {0!s}".format(tokenGroupsSet.difference(T)))