Example #1
0
    def assertXFluidDBHeaderForType(self, method, value, expectedTypeString):
        """
        Helper method to check if a resource is returning the appropriate
        C{X-FluidDB-Type} header for a given HTTP method.

        @param method: The HTTP method to use. Should be 'GET' or 'HEAD'.
        @param value: The value to test.
        @param expectedTypeString: The expected string that should be returned
            by C{X-FluidDB-Type}.
        """
        facadeClient = FakeFacade()
        session = FakeSession()

        # Tell our FakeFacade to preload some data for a given tag.
        facadeClient.values = {
            'fe2f50c8-997f-4049-a180-9a37543d001d': {
                'tag/test': value}}

        resource = TagInstanceResource(facadeClient, session,
                                       'fe2f50c8-997f-4049-a180-9a37543d001d',
                                       'tag/test')

        request = FakeRequest(method=method)
        yield getattr(resource, 'render_' + method)(request)
        typeValue = request.getResponseHeader(buildHeader('Type'))
        self.assertEqual(expectedTypeString, typeValue)
Example #2
0
    def testRenderWithSuccessfulVerification(self):
        """
        An C{OK} HTTP status code is returned, along with new access and
        renewal tokens, if a renewal request is successful.
        """
        UserAPI().create(
            [(u'consumer', 'secret', u'Consumer', u'*****@*****.**'),
             (u'user', 'secret', u'User', u'*****@*****.**')])
        consumer = getUser(u'consumer')
        user = getUser(u'consumer')
        api = OAuthConsumerAPI()
        api.register(consumer)
        token = api.getRenewalToken(consumer, user)
        self.store.commit()

        headers = {'X-FluidDB-Renewal-Token': [token.encrypt()]}
        request = FakeRequest(headers=Headers(headers))
        with login(u'consumer', consumer.objectID, self.transact) as session:
            resource = RenewOAuthTokenResource(session)
            self.assertEqual(NOT_DONE_YET, resource.render_GET(request))

            yield resource.deferred
            headers = dict(request.responseHeaders.getAllRawHeaders())
            self.assertTrue(headers['X-Fluiddb-Access-Token'])
            self.assertTrue(headers['X-Fluiddb-Renewal-Token'])
            self.assertEqual(OK, request.code)
Example #3
0
    def testRenderWithUnknownConsumer(self):
        """
        A C{BAD_REQUEST} HTTP status code is returned if an
        L{OAuthRenewalToken} for an unknown L{OAuthConsumer} is used in a
        renewal request.
        """
        UserAPI().create(
            [(u'consumer', 'secret', u'Consumer', u'*****@*****.**'),
             (u'user', 'secret', u'User', u'*****@*****.**')])
        consumer = getUser(u'consumer')
        user = getUser(u'consumer')
        api = OAuthConsumerAPI()
        api.register(consumer)
        token = api.getRenewalToken(consumer, user)
        headers = {'X-FluidDB-Renewal-Token': [token.encrypt()]}
        self.store.find(OAuthConsumer).remove()
        self.store.commit()

        request = FakeRequest(headers=Headers(headers))
        with login(u'consumer', consumer.objectID, self.transact) as session:
            resource = RenewOAuthTokenResource(session)
            self.assertEqual(NOT_DONE_YET, resource.render_GET(request))
            yield resource.deferred
            headers = dict(request.responseHeaders.getAllRawHeaders())
            self.assertEqual(
                {'X-Fluiddb-Error-Class': ['UnknownConsumer'],
                 'X-Fluiddb-Username': ['consumer'],
                 'X-Fluiddb-Request-Id': [session.id]},
                headers)
            self.assertEqual(BAD_REQUEST, request.code)
Example #4
0
 def testRenderRecentUserActivity(self):
     """
     L{RecentUserActivityResource.deferred_render_GET} renders a response
     with recent activity data for the given user.
     """
     objectID = ObjectAPI(self.user).create(u'object1')
     TagValueAPI(self.user).set({objectID: {u'username/tag1': u'A'}})
     self.store.commit()
     TagValueAPI(self.user).set({objectID: {u'username/tag2': u'B'}})
     self.store.commit()
     request = FakeRequest()
     with login(u'username', self.user.objectID, self.transact) as session:
         resource = RecentUserActivityResource(self.facade, session,
                                               u'username')
         body = yield resource.deferred_render_GET(request)
         body = json.loads(body)
         expected = [{
             u'username': u'username',
             u'about': u'object1',
             u'id': str(objectID),
             u'tag': u'username/tag2',
             u'value': u'B'
         }, {
             u'username': u'username',
             u'about': u'object1',
             u'id': str(objectID),
             u'tag': u'username/tag1',
             u'value': u'A'
         }]
         # Clean up timestamps.
         for item in body:
             del item['updated-at']
         self.assertEqual(expected, body)
         self.assertEqual(http.OK, request.code)
Example #5
0
 def testRenderRecentUsersActivity(self):
     """
     L{RecentUsersActivityResource.deferred_render_GET} renders a response
     with recent activity data by the users returned by the given query.
     """
     objectID = ObjectAPI(self.user).create(u'object1')
     self.store.commit()
     TagValueAPI(self.user).set({objectID: {u'username/tag1': u'A'}})
     runDataImportHandler(self.client.url)
     request = FakeRequest(
         args={'query': ['fluiddb/users/username = "******"']})
     with login(u'username', self.user.objectID, self.transact) as session:
         resource = RecentUsersActivityResource(self.facade, session)
         body = yield resource.deferred_render_GET(request)
         body = json.loads(body)
         expected = [{
             u'about': u'object1',
             u'id': str(objectID),
             u'tag': u'username/tag1',
             u'username': u'username',
             u'value': u'A'
         }]
         # Clean up timestamps.
         for item in body:
             del item['updated-at']
         self.assertEqual(expected, body)
         self.assertEqual(http.OK, request.code)
Example #6
0
    def testRenderWithUserConflict(self):
        """
        A C{CONFLICT} HTTP status code is returned if the authorization is
        successfully verified by the service provider, but the username
        clashes with an existing L{User} that isn't linked to the Twitter UID.
        The offending username is returned UTF-8 and base64 encoded.
        """
        username = u'john\N{HIRAGANA LETTER A}'
        UserAPI().create([(username, 'secret', u'John', u'*****@*****.**')])
        self.store.commit()

        self.agent._connect = self._connect
        headers = {
            'X-Verify-Credentials-Authorization': ['OAuth ...'],
            'X-Auth-Service-Provider': [TWITTER_URL]
        }
        request = FakeRequest(headers=Headers(headers))
        with login(u'anon', self.anonymous.objectID, self.transact) as session:
            resource = OAuthEchoResource(session, self.agent)
            self.assertEqual(NOT_DONE_YET, resource.render_GET(request))

            [(_, responseDeferred)] = self.protocol.requests
            data = {'id': 1984245, 'screen_name': username, 'name': u'John'}
            response = FakeResponse(ResponseDone(), dumps(data))
            responseDeferred.callback(response)
            yield resource.deferred
            self.assertEqual(CONFLICT, request.code)
            headers = dict(request.responseHeaders.getAllRawHeaders())
            encodedUsername = b64encode(username.encode('utf-8'))
            self.assertEqual(
                {
                    'X-Fluiddb-Error-Class': ['UsernameConflict'],
                    'X-Fluiddb-Username': [encodedUsername],
                    'X-Fluiddb-Request-Id': [session.id]
                }, headers)
Example #7
0
    def testRenderWithExpiredRenewalToken(self):
        """
        An C{UNAUTHORIZED} HTTP status code is returned if an expired
        L{OAuthRenewalToken} is used in a renewal request.
        """
        UserAPI().create(
            [(u'consumer', 'secret', u'Consumer', u'*****@*****.**'),
             (u'user', 'secret', u'User', u'*****@*****.**')])
        consumer = getUser(u'consumer')
        user = getUser(u'consumer')
        api = OAuthConsumerAPI()
        api.register(consumer)
        creationTime = datetime.utcnow() - timedelta(hours=200)
        token = api.getRenewalToken(consumer, user, now=lambda: creationTime)
        self.store.commit()

        headers = {'X-FluidDB-Renewal-Token': [token.encrypt()]}
        request = FakeRequest(headers=Headers(headers))
        with login(u'consumer', consumer.objectID, self.transact) as session:
            resource = RenewOAuthTokenResource(session)
            self.assertEqual(NOT_DONE_YET, resource.render_GET(request))
            yield resource.deferred
            headers = dict(request.responseHeaders.getAllRawHeaders())
            self.assertEqual(
                {'X-Fluiddb-Error-Class': ['ExpiredOAuth2RenewalToken'],
                 'X-Fluiddb-Username': ['consumer'],
                 'X-Fluiddb-Request-Id': [session.id]},
                headers)
            self.assertEqual(UNAUTHORIZED, request.code)
Example #8
0
    def testInsecurePostIsRejected(self):
        """A C{POST} via HTTP is rejected if not in development mode."""
        self.config.set('service', 'development', 'false')
        with login(None, None, self.transact) as session:
            resource = VerifyUserPasswordResource(None, session, 'user')
            payload = ''
            headers = {'Content-Length': [str(len(payload))],
                       'Content-Type': ['application/json']}
            request = FakeRequest(method='POST', headers=Headers(headers),
                                  body=payload)
            self.assertEqual(NOT_DONE_YET, resource.render(request))

            yield resource.deferred
            self.assertEqual(request.code, http.BAD_REQUEST)
            self.assertEqual(
                request.getResponseHeader('X-FluidDB-Message'),
                '/users/<username>/verify requests must use HTTPS')
Example #9
0
 def testGetChildForNone(self):
     """
     L{RecentActivityResource.getChild} returns a
     L{NoResource} for any other requests.
     """
     resource = RecentActivityResource(None, None)
     request = FakeRequest(postpath=[])
     leafResource = resource.getChild('invalid', request)
     self.assertIsInstance(leafResource, NoResource)
Example #10
0
 def testGetChildForItself(self):
     """
     L{RecentActivityResource.getChild} returns itself for requests without
     name.
     """
     resource = RecentActivityResource(None, None)
     request = FakeRequest(postpath=[])
     leafResource = resource.getChild('', request)
     self.assertIsInstance(leafResource, RecentActivityResource)
Example #11
0
 def testGetChildForUsers(self):
     """
     L{RecentActivityResource.getChild} returns a
     L{RecentUsersActivityResource} to handle C{recent/users} requests.
     """
     resource = RecentActivityResource(None, None)
     username = '******'
     request = FakeRequest(postpath=[username])
     leafResource = resource.getChild('users', request)
     self.assertIsInstance(leafResource, RecentUsersActivityResource)
Example #12
0
 def testGetChildForObjects(self):
     """
     L{RecentActivityResource.getChild} returns a
     L{RecentObjectsActivityResource} to handle C{recent/objects} requests.
     """
     resource = RecentActivityResource(None, None)
     objectID = '751ba46f-2f27-4ec3-9271-ff032bd60240'
     request = FakeRequest(postpath=[objectID])
     leafResource = resource.getChild('objects', request)
     self.assertIsInstance(leafResource, RecentObjectsActivityResource)
Example #13
0
 def testSimpleFailingMethodLogsTheResponsePayload(self):
     """A failing method logs the response payload."""
     body = dumps({'id': 100, 'jsonrpc': '2.0', 'method': 'fail',
                   'params': {}})
     headers = Headers({'Content-Length': [str(len(body))],
                        'Content-Type': ['application/json']})
     request = FakeRequest(headers=headers, body=body)
     resource = TestResource(None, None)
     yield resource.deferred_render_POST(request)
     self.assertIn('Response payload: ', self.log.getvalue())
Example #14
0
 def testSimpleFailingMethodReturnsRequestIDInResponseHeader(self):
     """A failing method returns an X-FluidDB-Request-Id HTTP header."""
     body = dumps({'id': 100, 'jsonrpc': '2.0', 'method': 'fail',
                   'params': {}})
     headers = Headers({'Content-Length': [str(len(body))],
                        'Content-Type': ['application/json']})
     request = FakeRequest(headers=headers, body=body)
     resource = TestResource(None, None)
     yield resource.deferred_render_POST(request)
     self.assertTrue(request.responseHeaders.hasHeader(
         'X-FluidDB-Request-Id'))
Example #15
0
 def testGetChildForAbout(self):
     """
     L{RecentActivityResource.getChild} returns a
     L{RecentAboutActivityResource} to handle C{recent/about} requests.
     """
     resource = RecentActivityResource(None, None)
     about = 'about'
     request = FakeRequest(postpath=[about])
     leafResource = resource.getChild('about', request)
     self.assertIsInstance(leafResource, RecentAboutActivityResource)
     self.assertEqual(about, leafResource.about)
Example #16
0
    def testPUTToUpdateRoleOnly(self):
        """
        A PUT request on C{/users/<username>} can update only the role for the
        user even if other arguments are not given.
        """
        body = dumps({'role': 'USER_MANAGER'})

        headers = Headers({'content-length': [len(body)],
                           'content-type': ['application/json']})

        request = FakeRequest(body=body, headers=headers)
        with login(u'username', self.user.objectID, self.transact) as session:
            resource = ConcreteUserResource(self.facade, session, 'username')
            yield resource.deferred_render_PUT(request)
            self.assertEqual(http.NO_CONTENT, request.code)
            body = yield resource.deferred_render_GET(FakeRequest())
            body = loads(body)
            expected = {'role': 'USER_MANAGER',
                        'name': 'User',
                        'id': str(self.user.objectID)}
            self.assertEqual(expected, body)
Example #17
0
 def testRequestWithoutHeader(self):
     """
     Non-HTTPS requests (with no C{X-Forwarded-Protocol} header) raise a
     L{LoginFailed} error.
     """
     request = FakeRequest(path='/',
                           uri='https://example.org/xx?arg=1',
                           headers=Headers(
                               {'X-FluidDB-Access-Token': ['xxx']}))
     response = b64encode('anon:anon')
     self.assertRaises(LoginFailed, self.credentialFactory.decode, response,
                       request)
Example #18
0
 def testSimpleEchoMethodWithListOfArgs(self):
     """A called method should be passed C{list} params."""
     body = dumps({'id': 100, 'jsonrpc': '2.0', 'method': 'pass',
                   'params': [39, 'steps']})
     headers = Headers({'Content-Length': [str(len(body))],
                        'Content-Type': ['application/json']})
     request = FakeRequest(headers=headers, body=body)
     resource = TestResource(None, None)
     result = yield resource.deferred_render_POST(request)
     response = loads(result)
     self.assertEqual({'args': [39, 'steps'], 'kwargs': {}},
                      response['result'])
Example #19
0
 def testRenderRecentAboutActivityWithUnknownAbout(self):
     """
     L{RecentUserActivityResource.deferred_render_GET} raises L{TNoSuchUser}
     if the given user doesn't exist.
     """
     self.store.commit()
     request = FakeRequest()
     with login(u'username', self.user.objectID, self.transact) as session:
         resource = RecentUserActivityResource(self.facade, session,
                                               u'unknown')
         deferred = resource.deferred_render_GET(request)
         yield self.assertFailure(deferred, TNoSuchUser)
Example #20
0
    def testDumpsAndLoads(self):
        """
        Data stored by an L{HTTPPlugin} can be dumped to and loaded from JSON.
        """
        headers = Headers({'x-foo': ['bar']})
        request = FakeRequest(uri='/objects',
                              method='PUT',
                              path='/objects?foo=bar',
                              headers=headers)
        session = SampleSession('id', self.transact)
        session.start()
        try:
            session.http.trace(request)
            request.setHeader('foo', 'bar')
            request.setResponseCode(FORBIDDEN)
        finally:
            session.stop()

        data = session.dumps()
        loadedSession = SampleSession('another-id', self.transact)
        loadedSession.loads(data)
        self.assertEqual(loadedSession.http.uri, session.http.uri)
        self.assertEqual(loadedSession.http.path, session.http.path)
        self.assertEqual(loadedSession.http.method, session.http.method)
        self.assertEqual(loadedSession.http.requestHeaders,
                         session.http.requestHeaders)
        self.assertEqual(loadedSession.http.responseHeaders,
                         session.http.responseHeaders)
        self.assertEqual(loadedSession.http.code, session.http.code)
Example #21
0
    def testTrace(self):
        """
        L{HTTPPlugin.trace} extracts and stores information from a request
        instance.
        """
        headers = Headers({'x-hello': ['goodbye']})
        request = FakeRequest(uri='/objects',
                              method='PUT',
                              path='/objects?foo=bar',
                              headers=headers)
        session = SampleSession('id', self.transact)
        session.start()
        try:
            session.http.trace(request)
            request.setHeader('foo', 'bar')
            request.setResponseCode(FORBIDDEN)
        finally:
            session.stop()

        self.assertEqual('/objects', session.http.uri)
        self.assertEqual('/objects?foo=bar', session.http.path)
        self.assertEqual('PUT', session.http.method)
        self.assertEqual(headers, session.http.requestHeaders)
        self.assertEqual({'Foo': ['bar']},
                         dict(session.http.responseHeaders.getAllRawHeaders()))
        self.assertEqual(FORBIDDEN, session.http.code)
Example #22
0
    def testRenderWithNewUser(self):
        """
        Missing L{User}s are created automatically and linked to
        L{TwitterUser}s for authorized UIDs.
        """
        self.assertNotIn(u'john', UserAPI().get([u'john']))
        self.store.commit()

        self.agent._connect = self._connect
        headers = {
            'X-Verify-Credentials-Authorization': ['OAuth ...'],
            'X-Auth-Service-Provider': [TWITTER_URL]
        }
        request = FakeRequest(headers=Headers(headers))
        with login(u'anon', self.anonymous.objectID, self.transact) as session:
            resource = OAuthEchoResource(session, self.agent)
            self.assertEqual(NOT_DONE_YET, resource.render_GET(request))

            [(_, responseDeferred)] = self.protocol.requests
            data = {'id': 1984245, 'screen_name': u'john', 'name': u'John'}
            response = FakeResponse(ResponseDone(), dumps(data))
            responseDeferred.callback(response)
            result = yield resource.deferred
            self.assertTrue(result['access-token'])
            self.assertTrue(result['renewal-token'])
            del result['access-token']
            del result['renewal-token']
            self.assertEqual(
                {
                    'username': u'john',
                    'new-user': True,
                    'missing-password': True,
                    'data': data,
                    'uid': 1984245
                }, result)
            self.assertEqual(OK, request.code)
            self.assertEqual(data, loads(request.written.getvalue()))
            headers = dict(request.responseHeaders.getAllRawHeaders())
            self.assertTrue(headers['X-Fluiddb-Access-Token'])
            self.assertTrue(headers['X-Fluiddb-Renewal-Token'])
            del headers['X-Fluiddb-Access-Token']
            del headers['X-Fluiddb-Renewal-Token']
            self.assertEqual(
                {
                    'X-Fluiddb-New-User': ['true'],
                    'X-Fluiddb-Missing-Password': ['true'],
                    'X-Fluiddb-Username': ['am9obg==']
                },  # username is in base64.
                headers)

            self.store.rollback()
            self.assertIn(u'john', UserAPI().get([u'john']))
Example #23
0
 def testSimpleFailingMethodReturnsVersion(self):
     """
     A failing method call should have the JSON RPC version in its body.
     """
     body = dumps({'id': 100, 'jsonrpc': '2.0', 'method': 'fail',
                   'params': [39, 'steps']})
     headers = Headers({'Content-Length': [str(len(body))],
                        'Content-Type': ['application/json']})
     request = FakeRequest(headers=headers, body=body)
     resource = TestResource(None, None)
     result = yield resource.deferred_render_POST(request)
     response = loads(result)
     self.assertEqual('2.0', response['jsonrpc'])
Example #24
0
    def testPUT(self):
        """
        A PUT request on C{/users/<username>} updates the data for the user.
        """
        body = dumps({'name': 'New name',
                      'email': '*****@*****.**',
                      'role': 'USER_MANAGER'})

        headers = Headers({'content-length': [len(body)],
                           'content-type': ['application/json']})

        request = FakeRequest(body=body, headers=headers)
        with login(u'username', self.user.objectID, self.transact) as session:
            resource = ConcreteUserResource(self.facade, session, 'username')
            yield resource.deferred_render_PUT(request)
            self.assertEqual(http.NO_CONTENT, request.code)
            body = yield resource.deferred_render_GET(FakeRequest())
            body = loads(body)
            expected = {'role': 'USER_MANAGER',
                        'name': 'New name',
                        'id': str(self.user.objectID)}
            self.assertEqual(expected, body)
Example #25
0
 def testRenderRecentAboutActivityWithNonexistentAboutValue(self):
     """
     L{RecentAboutActivityResource.deferred_render_GET} renders an empty
     list if the given object doesn't exist.
     """
     self.store.commit()
     request = FakeRequest()
     with login(u'username', self.user.objectID, self.transact) as session:
         resource = RecentAboutActivityResource(self.facade, session,
                                                u'unknown')
         body = yield resource.deferred_render_GET(request)
         body = json.loads(body)
         self.assertEqual([], body)
         self.assertEqual(http.OK, request.code)
Example #26
0
 def testLongRequestPayloadIsTruncatedInErrorLog(self):
     """
     A failing call that sends a long payload must have the request
     payload truncated in the log.
     """
     body = dumps({'id': 100, 'jsonrpc': '2.0', 'method': 'fail',
                   'params': {'long': '+' * 1000}})
     headers = Headers({'Content-Length': [str(len(body))],
                        'Content-Type': ['application/json']})
     request = FakeRequest(headers=headers, body=body)
     resource = TestResource(None, None)
     yield resource.deferred_render_POST(request)
     self.assertIn('... <payload truncated for logging>',
                   self.log.getvalue())
Example #27
0
 def testRenderRecentObjectActivityWithNoQuery(self):
     """
     L{RecentUsersActivityResource.deferred_render_GET} raises
     L{MissingArgument} if the C{query} argument is not given.
     """
     objectID = ObjectAPI(self.user).create(u'object1')
     self.store.commit()
     TagValueAPI(self.user).set({objectID: {u'username/tag1': u'A'}})
     runDataImportHandler(self.client.url)
     request = FakeRequest()
     with login(u'username', self.user.objectID, self.transact) as session:
         resource = RecentUsersActivityResource(self.facade, session)
         deferred = resource.deferred_render_GET(request)
         yield self.assertFailure(deferred, MissingArgument)
Example #28
0
    def testInsecurePostIsNotRejectedInDevelopmentMode(self):
        """A C{POST} via HTTP is not rejected when in development mode."""
        self.config.set('service', 'development', 'true')
        with login(None, None, self.transact) as session:
            resource = VerifyUserPasswordResource(None, session, 'user')
            payload = dumps({'password': '******'})
            headers = {'Content-Length': [str(len(payload))],
                       'Content-Type': ['application/json']}
            request = FakeRequest(method='POST', headers=Headers(headers),
                                  body=payload)
            self.assertEqual(NOT_DONE_YET, resource.render(request))

            yield resource.deferred
            self.assertEqual(request.code, http.OK)
Example #29
0
 def testSimpleEchoMethodReturnsId(self):
     """
     A successful method call should include the id from the request in
     its body.
     """
     body = dumps({'id': 300, 'jsonrpc': '2.0', 'method': 'pass',
                   'params': [39, 'steps']})
     headers = Headers({'Content-Length': [str(len(body))],
                        'Content-Type': ['application/json']})
     request = FakeRequest(headers=headers, body=body)
     resource = TestResource(None, None)
     result = yield resource.deferred_render_POST(request)
     response = loads(result)
     self.assertEqual(300, response['id'])
Example #30
0
 def testDecodeWithUnsplittableBasicAuthCredentials(self):
     """
     L{OAuth2CredentialFactory.decode} raises L{LoginFailed} if passed
     Basic Auth credentials that cannot be split on ':'.
     """
     response = 'unsplittable'
     request = FakeRequest(path='/',
                           uri='https://example.org/xx?arg=1',
                           headers=Headers({
                               'X-FluidDB-Access-Token': ['xxx'],
                               'X-Forwarded-Protocol': ['https']
                           }))
     self.assertRaises(LoginFailed, self.credentialFactory.decode, response,
                       request)