Example #1
0
class DPSClientSingleDirectoryTest(unittest.TestCase):
    """
    Tests the client against a single directory service (as opposed to the
    augmented, aggregated structure you get from directoryFromConfig(), which
    is tested in the class below)
    """
    def setUp(self):

        # The "local" directory service
        self.directory = DirectoryService(None)

        # The "remote" directory service
        if testMode == "xml":
            # Need a copy as it might change
            path = FilePath(os.path.join(os.path.dirname(__file__),
                                         "test.xml"))
            copy = FilePath(self.mktemp())
            path.copyTo(copy)
            remoteDirectory = CalendarXMLDirectoryService(copy)
        elif testMode == "od":
            remoteDirectory = CalendarODDirectoryService()

        # Connect the two services directly via an IOPump
        client = AMP()
        server = DirectoryProxyAMPProtocol(remoteDirectory)
        pump = returnConnected(server, client)

        # Replace the normal _getConnection method with one that bypasses any
        # actual networking
        self.patch(self.directory, "_getConnection", lambda: succeed(client))

        # Wrap the normal _sendCommand method with one that flushes the IOPump
        # afterwards
        origCall = self.directory._sendCommand

        def newCall(*args, **kwds):
            d = origCall(*args, **kwds)
            pump.flush()
            return d

        self.patch(self.directory, "_sendCommand", newCall)

    @inlineCallbacks
    def test_uid(self):
        record = (yield self.directory.recordWithUID(testUID))
        self.assertTrue(testShortName in record.shortNames)

    @inlineCallbacks
    def test_shortName(self):
        record = (yield
                  self.directory.recordWithShortName(RecordType.user,
                                                     testShortName))
        self.assertEquals(record.uid, testUID)

    @inlineCallbacks
    def test_guid(self):
        if testMode == "od":
            record = (yield self.directory.recordWithGUID(testUID))
            self.assertTrue(testShortName in record.shortNames)

    @inlineCallbacks
    def test_recordType(self):
        if testMode != "od":
            records = (yield
                       self.directory.recordsWithRecordType(RecordType.user))
            self.assertEquals(len(records), 9)

    @inlineCallbacks
    def test_emailAddress(self):
        if testMode == "xml":
            records = (yield self.directory.recordsWithEmailAddress(
                u"*****@*****.**"))
            self.assertEquals(len(records), 1)
            self.assertEquals(records[0].shortNames, [u"cdaboo"])

    @inlineCallbacks
    def test_recordsMatchingTokens(self):
        records = (yield self.directory.recordsMatchingTokens([u"anche"]))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_anyType(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive,
             MatchType.contains),
            (u"fullNames", "morgen", MatchFlags.caseInsensitive,
             MatchType.contains),
        )
        records = (yield
                   self.directory.recordsMatchingFields(fields,
                                                        operand=Operand.OR,
                                                        recordType=None))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("sagen" in matchingShortNames)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_oneType(self):
        fields = ((u"fullNames", "anche", MatchFlags.caseInsensitive,
                   MatchType.contains), )
        records = (yield self.directory.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=RecordType.user))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        # This location should *not* appear in the results
        self.assertFalse("sanchezoffice" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_unsupportedField(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive,
             MatchType.contains),
            # This should be ignored:
            (u"foo", "bar", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield
                   self.directory.recordsMatchingFields(fields,
                                                        operand=Operand.OR,
                                                        recordType=None))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_nonUnicode(self):
        fields = ((u"guid", uuid.UUID("A3B1158F-0564-4F5B-81E4-A89EA5FF81B0"),
                   MatchFlags.caseInsensitive, MatchType.equals), )
        records = (yield
                   self.directory.recordsMatchingFields(fields,
                                                        operand=Operand.OR,
                                                        recordType=None))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertFalse("wsanchez" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_not(self):
        fields = ((u"fullNames", "anche",
                   MatchFlags.NOT | MatchFlags.caseInsensitive,
                   MatchType.contains), )
        records = (yield
                   self.directory.recordsMatchingFields(fields,
                                                        operand=Operand.OR,
                                                        recordType=None))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("sagen" in matchingShortNames)
        self.assertTrue("dre" not in matchingShortNames)
        self.assertTrue("wsanchez" not in matchingShortNames)
        self.assertTrue("sanchezoffice" not in matchingShortNames)

    @inlineCallbacks
    def test_recordsFromMatchExpression(self):
        expression = MatchExpression(FieldName.uid, testUID, MatchType.equals,
                                     MatchFlags.none)
        records = yield self.directory.recordsFromExpression(expression)
        self.assertEquals(len(records), 1)

    test_recordsFromMatchExpression.todo = "Won't work until we can serialize expressions"

    @inlineCallbacks
    def test_members(self):
        group = yield self.directory.recordWithUID(u"__calendar-dev__")
        members = yield group.members()
        self.assertEquals(len(members), 5)

    @inlineCallbacks
    def test_groups(self):
        # No need to use group cacher as the XML service directly supports
        # groups()
        record = yield self.directory.recordWithUID(u"__sagen__")
        groups = yield record.groups()
        self.assertEquals(len(groups), 1)

    @inlineCallbacks
    def test_group_changes(self):
        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 5)

        # Add new member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__cdaboo__")
        yield group.addMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 6)

        # Add existing member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__wsanchez__")
        yield group.addMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 6)

        # Remove existing member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__cdaboo__")
        yield group.removeMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 5)

        # Remove missing member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__cdaboo__")
        yield group.removeMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 5)

    @inlineCallbacks
    def test_verifyPlaintextPassword(self):
        expectations = (
            (testPassword, True),  # Correct
            ("wrong", False),  # Incorrect
            ("wrong\xc3\xa5", False),  # Incorrect
        )
        record = (yield
                  self.directory.recordWithShortName(RecordType.user,
                                                     testShortName))

        for password, answer in expectations:
            authenticated = (yield record.verifyPlaintextPassword(password))
            self.assertEquals(authenticated, answer)

    @inlineCallbacks
    def test_verifyHTTPDigest(self):
        expectations = (
            (testPassword, True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (yield
                  self.directory.recordWithShortName(RecordType.user,
                                                     testShortName))

        realm = "host.example.com"
        nonce = "128446648710842461101646794502"
        algorithm = "md5"
        uri = "http://host.example.com"
        method = "GET"

        for password, answer in expectations:
            for qop, nc, cnonce in (
                ("", "", ""),
                ("auth", "00000001",
                 "/rrD6TqPA3lHRmg+fw/vyU6oWoQgzK7h9yWrsCmv/lE="),
            ):
                response = calcResponse(
                    calcHA1(algorithm, testShortName, realm, password,
                            nonce, cnonce),
                    calcHA2(algorithm, method, uri, qop, None), algorithm,
                    nonce, nc, cnonce, qop)

                authenticated = (yield record.verifyHTTPDigest(
                    testShortName, realm, uri, nonce, cnonce, algorithm, nc,
                    qop, response, method))
                self.assertEquals(authenticated, answer)
Example #2
0
class DPSClientSingleDirectoryTest(unittest.TestCase):
    """
    Tests the client against a single directory service (as opposed to the
    augmented, aggregated structure you get from directoryFromConfig(), which
    is tested in the class below)
    """

    def setUp(self):

        # The "local" directory service
        self.directory = DirectoryService(None)

        # The "remote" directory service
        if testMode == "xml":
            # Need a copy as it might change
            path = FilePath(os.path.join(os.path.dirname(__file__), "test.xml"))
            copy = FilePath(self.mktemp())
            path.copyTo(copy)
            remoteDirectory = CalendarXMLDirectoryService(copy)
        elif testMode == "od":
            remoteDirectory = CalendarODDirectoryService()

        # Connect the two services directly via an IOPump
        client = AMP()
        server = DirectoryProxyAMPProtocol(remoteDirectory)
        pump = returnConnected(server, client)

        # Replace the normal _getConnection method with one that bypasses any
        # actual networking
        self.patch(self.directory, "_getConnection", lambda: succeed(client))

        # Wrap the normal _sendCommand method with one that flushes the IOPump
        # afterwards
        origCall = self.directory._sendCommand

        def newCall(*args, **kwds):
            d = origCall(*args, **kwds)
            pump.flush()
            return d

        self.patch(self.directory, "_sendCommand", newCall)


    @inlineCallbacks
    def test_uid(self):
        record = (yield self.directory.recordWithUID(testUID))
        self.assertTrue(testShortName in record.shortNames)


    @inlineCallbacks
    def test_shortName(self):
        record = (yield self.directory.recordWithShortName(
            RecordType.user,
            testShortName
        ))
        self.assertEquals(record.uid, testUID)


    @inlineCallbacks
    def test_guid(self):
        if testMode == "od":
            record = (yield self.directory.recordWithGUID(testUID))
            self.assertTrue(testShortName in record.shortNames)


    @inlineCallbacks
    def test_recordType(self):
        if testMode != "od":
            records = (yield self.directory.recordsWithRecordType(
                RecordType.user
            ))
            self.assertEquals(len(records), 9)


    @inlineCallbacks
    def test_emailAddress(self):
        if testMode == "xml":
            records = (yield self.directory.recordsWithEmailAddress(
                u"*****@*****.**"
            ))
            self.assertEquals(len(records), 1)
            self.assertEquals(records[0].shortNames, [u"cdaboo"])


    @inlineCallbacks
    def test_recordsMatchingTokens(self):
        records = (yield self.directory.recordsMatchingTokens(
            [u"anche"]
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_anyType(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive, MatchType.contains),
            (u"fullNames", "morgen", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.directory.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=None
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("sagen" in matchingShortNames)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_oneType(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.directory.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=RecordType.user
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        # This location should *not* appear in the results
        self.assertFalse("sanchezoffice" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_unsupportedField(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive, MatchType.contains),
            # This should be ignored:
            (u"foo", "bar", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.directory.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=None
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_nonUnicode(self):
        fields = (
            (u"guid", uuid.UUID("A3B1158F-0564-4F5B-81E4-A89EA5FF81B0"),
                MatchFlags.caseInsensitive, MatchType.equals),
        )
        records = (yield self.directory.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=None
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertFalse("wsanchez" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_not(self):
        fields = (
            (
                u"fullNames", "anche",
                MatchFlags.NOT | MatchFlags.caseInsensitive,
                MatchType.contains
            ),
        )
        records = (yield self.directory.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=None
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("sagen" in matchingShortNames)
        self.assertTrue("dre" not in matchingShortNames)
        self.assertTrue("wsanchez" not in matchingShortNames)
        self.assertTrue("sanchezoffice" not in matchingShortNames)


    @inlineCallbacks
    def test_recordsFromMatchExpression(self):
        expression = MatchExpression(
            FieldName.uid,
            testUID,
            MatchType.equals,
            MatchFlags.none
        )
        records = yield self.directory.recordsFromExpression(expression)
        self.assertEquals(len(records), 1)

    test_recordsFromMatchExpression.todo = "Won't work until we can serialize expressions"


    @inlineCallbacks
    def test_members(self):
        group = yield self.directory.recordWithUID(u"__calendar-dev__")
        members = yield group.members()
        self.assertEquals(len(members), 5)


    @inlineCallbacks
    def test_groups(self):
        # No need to use group cacher as the XML service directly supports
        # groups()
        record = yield self.directory.recordWithUID(u"__sagen__")
        groups = yield record.groups()
        self.assertEquals(len(groups), 1)


    @inlineCallbacks
    def test_group_changes(self):
        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 5)

        # Add new member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__cdaboo__")
        yield group.addMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 6)

        # Add existing member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__wsanchez__")
        yield group.addMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 6)

        # Remove existing member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__cdaboo__")
        yield group.removeMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 5)

        # Remove missing member
        group = yield self.directory.recordWithUID(u"__twisted__")
        user = yield self.directory.recordWithUID(u"__cdaboo__")
        yield group.removeMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__twisted__")
        members = yield group.members()
        self.assertEquals(len(members), 5)


    @inlineCallbacks
    def test_verifyPlaintextPassword(self):
        expectations = (
            (testPassword, True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (
            yield self.directory.recordWithShortName(
                RecordType.user,
                testShortName
            )
        )

        for password, answer in expectations:
            authenticated = (yield record.verifyPlaintextPassword(password))
            self.assertEquals(authenticated, answer)


    @inlineCallbacks
    def test_verifyHTTPDigest(self):
        expectations = (
            (testPassword, True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (
            yield self.directory.recordWithShortName(
                RecordType.user,
                testShortName
            )
        )

        realm = "host.example.com"
        nonce = "128446648710842461101646794502"
        algorithm = "md5"
        uri = "http://host.example.com"
        method = "GET"

        for password, answer in expectations:
            for qop, nc, cnonce in (
                ("", "", ""),
                ("auth", "00000001", "/rrD6TqPA3lHRmg+fw/vyU6oWoQgzK7h9yWrsCmv/lE="),
            ):
                response = calcResponse(
                    calcHA1(algorithm, testShortName, realm, password, nonce, cnonce),
                    calcHA2(algorithm, method, uri, qop, None),
                    algorithm, nonce, nc, cnonce, qop)

                authenticated = (
                    yield record.verifyHTTPDigest(
                        testShortName, realm, uri, nonce, cnonce, algorithm, nc, qop,
                        response, method
                    )
                )
                self.assertEquals(authenticated, answer)
Example #3
0
class DPSClientAugmentedAggregateDirectoryTest(StoreTestCase):
    """
    Similar to the above tests, but in the context of the directory structure
    that directoryFromConfig() returns
    """

    wsanchezUID = u"6423F94A-6B76-4A3A-815B-D52CFD77935D"

    @inlineCallbacks
    def setUp(self):
        yield super(DPSClientAugmentedAggregateDirectoryTest, self).setUp()

        # The "local" directory service
        self.client = DirectoryService(None)

        # The "remote" directory service
        remoteDirectory = self.directory

        # Connect the two services directly via an IOPump
        client = AMP()
        server = DirectoryProxyAMPProtocol(remoteDirectory)
        pump = returnConnected(server, client)

        # Replace the normal _getConnection method with one that bypasses any
        # actual networking
        self.patch(self.client, "_getConnection", lambda: succeed(client))

        # Wrap the normal _sendCommand method with one that flushes the IOPump
        # afterwards
        origCall = self.client._sendCommand

        def newCall(*args, **kwds):
            d = origCall(*args, **kwds)
            pump.flush()
            return d

        self.patch(self.client, "_sendCommand", newCall)

    def configure(self):
        """
        Override configuration hook to turn on wiki.
        """
        super(DPSClientAugmentedAggregateDirectoryTest, self).configure()
        self.patch(config.Authentication.Wiki, "Enabled", True)

    @inlineCallbacks
    def test_setAutoScheduleMode(self):
        """
        Verify setAutoSchedule works across DPS
        """
        record = yield self.client.recordWithUID(
            u"75EA36BE-F71B-40F9-81F9-CF59BF40CA8F")
        # Defaults to automatic
        self.assertEquals(record.autoScheduleMode,
                          AutoScheduleMode.acceptIfFreeDeclineIfBusy)
        # Change it to accept-if-busy
        yield record.setAutoScheduleMode(AutoScheduleMode.acceptIfFree)
        # Refetch it
        record = yield self.client.recordWithUID(
            u"75EA36BE-F71B-40F9-81F9-CF59BF40CA8F")
        # Verify it's changed
        self.assertEquals(record.autoScheduleMode,
                          AutoScheduleMode.acceptIfFree)

    @inlineCallbacks
    def test_uid(self):
        record = (yield self.client.recordWithUID(self.wsanchezUID))
        self.assertTrue(u"wsanchez" in record.shortNames)

    @inlineCallbacks
    def test_shortName(self):
        record = (yield
                  self.client.recordWithShortName(RecordType.user,
                                                  u"wsanchez"))
        self.assertEquals(record.uid, self.wsanchezUID)

    @inlineCallbacks
    def test_guid(self):
        record = yield self.client.recordWithGUID(self.wsanchezUID)
        self.assertTrue(u"wsanchez" in record.shortNames)

    @inlineCallbacks
    def test_recordType(self):
        records = (yield self.client.recordsWithRecordType(RecordType.user))
        self.assertEquals(len(records), 244)

    @inlineCallbacks
    def test_emailAddress(self):
        records = (
            yield self.client.recordsWithEmailAddress(u"*****@*****.**"))
        self.assertEquals(len(records), 1)
        self.assertEquals(records[0].shortNames, [u"wsanchez"])

    @inlineCallbacks
    def test_recordsMatchingTokens(self):
        records = (yield self.client.recordsMatchingTokens([u"anche"]))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingTokensWithContext(self):

        testData = [
            # (
            #     tokens,
            #     context,
            #     short names expected to be in results,
            #     short names not expected to be in results
            # ),
            (
                [u"an"],
                "user",  # just users
                (u"dre", u"wsanchez"),
                (u"transporter", u"managers"),
            ),
            (
                [u"an"],
                "group",  # just groups
                (u"managers", ),
                (u"dre", u"wsanchez", u"transporter"),
            ),
            (
                [u"an"],
                "location",  # just locations
                (u"sanchezoffice", ),
                (u"dre", u"wsanchez", u"transporter", u"managers"),
            ),
            (
                [u"an"],
                "resource",  # just resources
                (u"transporter", u"ftlcpu"),
                (u"dre", u"wsanchez", u"managers", u"sanchezoffice"),
            ),
            (
                [u"an"],
                "attendee",  # just users, groups, resources
                (u"dre", u"wsanchez", u"managers", u"transporter", u"ftlcpu"),
                (u"sanchezoffice", ),
            ),
            (
                [u"an"],
                None,  # any type
                (u"dre", u"wsanchez", u"managers", u"sanchezoffice",
                 u"transporter", u"ftlcpu"),
                (),
            ),
        ]

        for tokens, context, expected, unexpected in testData:
            # print("Tokens", tokens, "context", context)
            records = yield self.directory.recordsMatchingTokens(
                tokens, context)
            matchingShortNames = set()
            for r in records:
                for shortName in r.shortNames:
                    matchingShortNames.add(shortName)
            for name in expected:
                self.assertTrue(name in matchingShortNames)
            for name in unexpected:
                self.assertFalse(name in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_anyType(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive,
             MatchType.contains),
            (u"fullNames", "morgen", MatchFlags.caseInsensitive,
             MatchType.contains),
        )
        records = (yield self.client.recordsMatchingFields(fields,
                                                           operand=Operand.OR,
                                                           recordType=None))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("sagen" in matchingShortNames)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_oneType(self):
        fields = ((u"fullNames", "anche", MatchFlags.caseInsensitive,
                   MatchType.contains), )
        records = (yield self.client.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=RecordType.user))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        # This location should *not* appear in the results
        self.assertFalse("sanchezoffice" in matchingShortNames)

    @inlineCallbacks
    def test_recordsMatchingFields_unsupportedField(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive,
             MatchType.contains),
            # This should be ignored:
            (u"foo", "bar", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.client.recordsMatchingFields(fields,
                                                           operand=Operand.OR,
                                                           recordType=None))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)

    @inlineCallbacks
    def test_recordsFromMatchExpression(self):
        expression = MatchExpression(FieldName.uid, u"wsanchez",
                                     MatchType.equals, MatchFlags.none)
        records = yield self.client.recordsFromExpression(expression)
        self.assertEquals(len(records), 1)

    test_recordsFromMatchExpression.todo = "Won't work until we can serialize expressions"

    @inlineCallbacks
    def test_members(self):
        group = yield self.client.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

        group = yield self.client.recordWithUID(u"emptygroup")
        members = yield group.members()
        self.assertEquals(len(members), 0)

    @inlineCallbacks
    def test_expandedMemberUIDs(self):
        group = yield self.client.recordWithUID(u"__top_group_1__")
        memberUIDs = yield group.expandedMemberUIDs()
        self.assertEquals(
            set(memberUIDs),
            set([
                u'__wsanchez1__', u'__cdaboo1__', u'__glyph1__', u'__sagen1__'
            ]))

    @inlineCallbacks
    def test_groups(self):

        # A group must first be "refreshed" into the DB otherwise we won't
        # consider it for group memberships
        txn = self.store.newTransaction()
        groupCacher = GroupCacher(self.directory)
        yield groupCacher.refreshGroup(txn, u"__sub_group_1__")
        yield txn.commit()

        # record = yield self.client.recordWithUID(u"__sagen1__")
        # FIXME: this call hangs during unit tests, but not in a real server:
        # groups = yield record.groups()
        # self.assertEquals(len(groups), 1)

    test_groups.todo = "Figure out why this hangs"

    @inlineCallbacks
    def test_group_changes(self):
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

        # Add new member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__cdaboo1__")
        yield group.addMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 4)

        # Add existing member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__wsanchez1__")
        yield group.addMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 4)

        # Remove existing member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__cdaboo1__")
        yield group.removeMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

        # Remove missing member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__cdaboo1__")
        yield group.removeMembers((user, ))
        yield self.directory.updateRecords((group, ), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

    @inlineCallbacks
    def test_verifyPlaintextPassword(self):
        expectations = (
            (u"zehcnasw", True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (yield
                  self.client.recordWithShortName(RecordType.user,
                                                  u"wsanchez"))

        for password, answer in expectations:
            authenticated = (yield record.verifyPlaintextPassword(password))
            self.assertEquals(authenticated, answer)

    @inlineCallbacks
    def test_verifyHTTPDigest(self):
        expectations = (
            (u"zehcnasw", True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (yield
                  self.client.recordWithShortName(RecordType.user,
                                                  u"wsanchez"))

        realm = "host.example.com"
        nonce = "128446648710842461101646794502"
        algorithm = "md5"
        uri = "http://host.example.com"
        method = "GET"

        for password, answer in expectations:
            for qop, nc, cnonce in (
                ("", "", ""),
                ("auth", "00000001",
                 "/rrD6TqPA3lHRmg+fw/vyU6oWoQgzK7h9yWrsCmv/lE="),
            ):
                response = calcResponse(
                    calcHA1(algorithm, u"wsanchez", realm, password,
                            nonce, cnonce),
                    calcHA2(algorithm, method, uri, qop, None), algorithm,
                    nonce, nc, cnonce, qop)

                authenticated = (yield record.verifyHTTPDigest(
                    u"wsanchez", realm, uri, nonce, cnonce, algorithm, nc, qop,
                    response, method))
                self.assertEquals(authenticated, answer)
Example #4
0
class DPSClientAugmentedAggregateDirectoryTest(StoreTestCase):
    """
    Similar to the above tests, but in the context of the directory structure
    that directoryFromConfig() returns
    """

    wsanchezUID = u"6423F94A-6B76-4A3A-815B-D52CFD77935D"

    @inlineCallbacks
    def setUp(self):
        yield super(DPSClientAugmentedAggregateDirectoryTest, self).setUp()

        # The "local" directory service
        self.client = DirectoryService(None)

        # The "remote" directory service
        remoteDirectory = self.directory

        # Connect the two services directly via an IOPump
        client = AMP()
        server = DirectoryProxyAMPProtocol(remoteDirectory)
        pump = returnConnected(server, client)

        # Replace the normal _getConnection method with one that bypasses any
        # actual networking
        self.patch(self.client, "_getConnection", lambda: succeed(client))

        # Wrap the normal _sendCommand method with one that flushes the IOPump
        # afterwards
        origCall = self.client._sendCommand

        def newCall(*args, **kwds):
            d = origCall(*args, **kwds)
            pump.flush()
            return d

        self.patch(self.client, "_sendCommand", newCall)


    def configure(self):
        """
        Override configuration hook to turn on wiki.
        """
        super(DPSClientAugmentedAggregateDirectoryTest, self).configure()
        self.patch(config.Authentication.Wiki, "Enabled", True)


    @inlineCallbacks
    def test_uid(self):
        record = (yield self.client.recordWithUID(self.wsanchezUID))
        self.assertTrue(u"wsanchez" in record.shortNames)


    @inlineCallbacks
    def test_shortName(self):
        record = (yield self.client.recordWithShortName(
            RecordType.user,
            u"wsanchez"
        ))
        self.assertEquals(record.uid, self.wsanchezUID)


    @inlineCallbacks
    def test_guid(self):
        record = yield self.client.recordWithGUID(self.wsanchezUID)
        self.assertTrue(u"wsanchez" in record.shortNames)


    @inlineCallbacks
    def test_recordType(self):
        records = (yield self.client.recordsWithRecordType(
            RecordType.user
        ))
        self.assertEquals(len(records), 244)


    @inlineCallbacks
    def test_emailAddress(self):
        records = (yield self.client.recordsWithEmailAddress(
            u"*****@*****.**"
        ))
        self.assertEquals(len(records), 1)
        self.assertEquals(records[0].shortNames, [u"wsanchez"])


    @inlineCallbacks
    def test_recordsMatchingTokens(self):
        records = (yield self.client.recordsMatchingTokens(
            [u"anche"]
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingTokensWithContext(self):

        testData = [
            # (
            #     tokens,
            #     context,
            #     short names expected to be in results,
            #     short names not expected to be in results
            # ),
            (
                [u"an"],
                "user",  # just users
                (u"dre", u"wsanchez"),
                (u"transporter", u"managers"),
            ),
            (
                [u"an"],
                "group",  # just groups
                (u"managers",),
                (u"dre", u"wsanchez", u"transporter"),
            ),
            (
                [u"an"],
                "location",  # just locations
                (u"sanchezoffice",),
                (u"dre", u"wsanchez", u"transporter", u"managers"),
            ),
            (
                [u"an"],
                "resource",  # just resources
                (u"transporter", u"ftlcpu"),
                (u"dre", u"wsanchez", u"managers", u"sanchezoffice"),
            ),
            (
                [u"an"],
                "attendee",  # just users, groups, resources
                (
                    u"dre", u"wsanchez", u"managers",
                    u"transporter", u"ftlcpu"
                ),
                (u"sanchezoffice",),
            ),
            (
                [u"an"],
                None,   # any type
                (
                    u"dre", u"wsanchez", u"managers", u"sanchezoffice",
                    u"transporter", u"ftlcpu"
                ),
                (),
            ),
        ]

        for tokens, context, expected, unexpected in testData:
            # print("Tokens", tokens, "context", context)
            records = yield self.directory.recordsMatchingTokens(
                tokens, context
            )
            matchingShortNames = set()
            for r in records:
                for shortName in r.shortNames:
                    matchingShortNames.add(shortName)
            for name in expected:
                self.assertTrue(name in matchingShortNames)
            for name in unexpected:
                self.assertFalse(name in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_anyType(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive, MatchType.contains),
            (u"fullNames", "morgen", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.client.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=None
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("sagen" in matchingShortNames)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_oneType(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.client.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=RecordType.user
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        # This location should *not* appear in the results
        self.assertFalse("sanchezoffice" in matchingShortNames)


    @inlineCallbacks
    def test_recordsMatchingFields_unsupportedField(self):
        fields = (
            (u"fullNames", "anche", MatchFlags.caseInsensitive, MatchType.contains),
            # This should be ignored:
            (u"foo", "bar", MatchFlags.caseInsensitive, MatchType.contains),
        )
        records = (yield self.client.recordsMatchingFields(
            fields, operand=Operand.OR, recordType=None
        ))
        matchingShortNames = set()
        for r in records:
            for shortName in r.shortNames:
                matchingShortNames.add(shortName)
        self.assertTrue("dre" in matchingShortNames)
        self.assertTrue("wsanchez" in matchingShortNames)
        self.assertTrue("sanchezoffice" in matchingShortNames)


    @inlineCallbacks
    def test_recordsFromMatchExpression(self):
        expression = MatchExpression(
            FieldName.uid,
            u"wsanchez",
            MatchType.equals,
            MatchFlags.none
        )
        records = yield self.client.recordsFromExpression(expression)
        self.assertEquals(len(records), 1)

    test_recordsFromMatchExpression.todo = "Won't work until we can serialize expressions"


    @inlineCallbacks
    def test_members(self):
        group = yield self.client.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

        group = yield self.client.recordWithUID(u"emptygroup")
        members = yield group.members()
        self.assertEquals(len(members), 0)


    @inlineCallbacks
    def test_expandedMemberUIDs(self):
        group = yield self.client.recordWithUID(u"__top_group_1__")
        memberUIDs = yield group.expandedMemberUIDs()
        self.assertEquals(
            set(memberUIDs),
            set(
                [u'__wsanchez1__', u'__cdaboo1__', u'__glyph1__', u'__sagen1__']
            )
        )


    @inlineCallbacks
    def test_groups(self):

        # A group must first be "refreshed" into the DB otherwise we won't
        # consider it for group memberships
        txn = self.store.newTransaction()
        groupCacher = GroupCacher(self.directory)
        yield groupCacher.refreshGroup(txn, u"__sub_group_1__")
        yield txn.commit()

        # record = yield self.client.recordWithUID(u"__sagen1__")
        # FIXME: this call hangs during unit tests, but not in a real server:
        # groups = yield record.groups()
        # self.assertEquals(len(groups), 1)

    test_groups.todo = "Figure out why this hangs"


    @inlineCallbacks
    def test_group_changes(self):
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

        # Add new member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__cdaboo1__")
        yield group.addMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 4)

        # Add existing member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__wsanchez1__")
        yield group.addMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 4)

        # Remove existing member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__cdaboo1__")
        yield group.removeMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)

        # Remove missing member
        group = yield self.directory.recordWithUID(u"__top_group_1__")
        user = yield self.directory.recordWithUID(u"__cdaboo1__")
        yield group.removeMembers((user,))
        yield self.directory.updateRecords((group,), False)

        group = yield self.directory.recordWithUID(u"__top_group_1__")
        members = yield group.members()
        self.assertEquals(len(members), 3)


    @inlineCallbacks
    def test_verifyPlaintextPassword(self):
        expectations = (
            (u"zehcnasw", True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (
            yield self.client.recordWithShortName(
                RecordType.user,
                u"wsanchez"
            )
        )

        for password, answer in expectations:
            authenticated = (yield record.verifyPlaintextPassword(password))
            self.assertEquals(authenticated, answer)


    @inlineCallbacks
    def test_verifyHTTPDigest(self):
        expectations = (
            (u"zehcnasw", True),  # Correct
            ("wrong", False)  # Incorrect
        )
        record = (
            yield self.client.recordWithShortName(
                RecordType.user,
                u"wsanchez"
            )
        )

        realm = "host.example.com"
        nonce = "128446648710842461101646794502"
        algorithm = "md5"
        uri = "http://host.example.com"
        method = "GET"

        for password, answer in expectations:
            for qop, nc, cnonce in (
                ("", "", ""),
                ("auth", "00000001", "/rrD6TqPA3lHRmg+fw/vyU6oWoQgzK7h9yWrsCmv/lE="),
            ):
                response = calcResponse(
                    calcHA1(algorithm, u"wsanchez", realm, password, nonce, cnonce),
                    calcHA2(algorithm, method, uri, qop, None),
                    algorithm, nonce, nc, cnonce, qop)

                authenticated = (
                    yield record.verifyHTTPDigest(
                        u"wsanchez", realm, uri, nonce, cnonce, algorithm, nc, qop,
                        response, method
                    )
                )
                self.assertEquals(authenticated, answer)