def testInvalidCORSPreFlightRequestNoACRM(self): """ The request has an Origin header but no Access-Control-Request-Method so check it returns a regular OPTIONS response. """ # The origin to use in the tests dummyOrigin = 'http://foo.com' request = http.Request(DummyChannel(), False) request.method = 'OPTIONS' request.requestHeaders.setRawHeaders('Origin', [dummyOrigin]) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = NoContent() resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource._handleOptions(request, dummyOrigin) # 200 OK self.assertEqual(request.code, http.OK) # check we have the required headers headers = request.responseHeaders self.assertTrue(headers.hasHeader('Allow')) # Check the allowed methods (including and in addition to those # allowed for CORS) allowedMethods = headers.getRawHeaders('Allow')[0].split(', ') self.assertEqual(len(resource.allowedMethods), len(allowedMethods)) for item in resource.allowedMethods: self.assertTrue(item in allowedMethods) # There are *NO* CORS related headers self.assertFalse(headers.hasHeader('Access-Control-Allow-Origin')) self.assertFalse(headers.hasHeader('Access-Control-Max-Age')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Credentials')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Methods'))
def testRegularOptionsCall(self): """ Validates that a regular non-CORS OPTIONS call returns an appropriate response """ request = http.Request(DummyChannel(), False) request.method = 'OPTIONS' request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = NoContent() resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource._handleOptions(request, None) # 200 OK self.assertEqual(request.code, http.OK) # check we have the required headers headers = request.responseHeaders self.assertTrue(headers.hasHeader('Allow')) # Check the allowed methods (including and in addition to those # allowed for CORS) allowedMethods = headers.getRawHeaders('Allow')[0].split(', ') self.assertEqual(len(resource.allowedMethods), len(allowedMethods)) for item in resource.allowedMethods: self.assertTrue(item in allowedMethods) # There are *NO* CORS related headers self.assertFalse(headers.hasHeader('Access-Control-Allow-Origin')) self.assertFalse(headers.hasHeader('Access-Control-Max-Age')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Credentials')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Methods'))
def testCorsHeadersDoNotAppearForRegularRequests(self): """ Make sure CORS related headers do NOT appear in regular non-CORS requests """ payload = { 'description': 'A namespace for tags I add to people', 'name': 'people' } content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders('Content-Length', [str(contentLength)]) request.requestHeaders.setRawHeaders('Content-Type', ['application/json']) request.requestHeaders.setRawHeaders('Host', ['fluiddb.fluidinfo.com']) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) # 201 Created self.assertEqual(request.code, http.CREATED) # check we don't have the CORS related headers headers = request.responseHeaders self.assertFalse(headers.hasHeader('Access-Control-Allow-Origin')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Credentials')) self.assertFalse(headers.hasHeader('Access-Control-Expose-Headers'))
def testRegularOptionsCall(self): """ Validates that a regular non-CORS OPTIONS call returns an appropriate response """ request = http.Request(DummyChannel(), False) request.method = 'OPTIONS' request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = NoContent() resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource._handleOptions(request, None) # 200 OK self.assertEqual(request.code, http.OK) # check we have the required headers headers = request.responseHeaders self.assertTrue(headers.hasHeader('Allow')) # Check the allowed methods (including and in addition to those # allowed for CORS) allowedMethods = headers.getRawHeaders('Allow')[0].split(', ') self.assertEqual( len(resource.allowedMethods), len(allowedMethods)) for item in resource.allowedMethods: self.assertTrue(item in allowedMethods) # There are *NO* CORS related headers self.assertFalse(headers.hasHeader('Access-Control-Allow-Origin')) self.assertFalse(headers.hasHeader('Access-Control-Max-Age')) self.assertFalse( headers.hasHeader('Access-Control-Allow-Credentials')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Methods'))
def testRegularCORSHeaders(self): """ Validates that the headers are handled correctly for a CORS request that doesn't use the OPTIONS verb """ # The origin to use in the tests dummyOrigin = 'http://foo.com' expectedHeaders = [ 'X-FluidDB-Error-Class', 'X-FluidDB-Path', 'X-FluidDB-Message', 'X-FluidDB-ObjectId', 'X-FluidDB-Name', 'X-FluidDB-Category', 'X-FluidDB-Action', 'X-FluidDB-Rangetype', 'X-FluidDB-Fieldname', 'X-FluidDB-Argument', 'X-FluidDB-Access-Token', 'X-FluidDB-Username', 'X-FluidDB-New-User' ] payload = { 'description': 'A namespace for tags that I add to people', 'name': 'people' } content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders('Content-Length', [str(contentLength)]) request.requestHeaders.setRawHeaders('Content-Type', ['application/json']) request.requestHeaders.setRawHeaders('Host', ['fluiddb.fluidinfo.com']) request.requestHeaders.setRawHeaders('Origin', [dummyOrigin]) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) # 201 Created self.assertEqual(request.code, http.CREATED) # check we have the required headers headers = request.responseHeaders self.assertTrue(headers.hasHeader('Access-Control-Allow-Origin')) self.assertTrue(headers.hasHeader('Access-Control-Allow-Credentials')) self.assertTrue(headers.hasHeader('Access-Control-Expose-Headers')) # check the values of the required headers self.assertEqual( dummyOrigin, headers.getRawHeaders('Access-Control-Allow-Origin')[0]) self.assertEqual( 'true', headers.getRawHeaders('Access-Control-Allow-Credentials')[0]) accessControlExposeHeaders = headers.getRawHeaders( 'Access-Control-Expose-Headers')[0] # Make sure we haven't accidentally turned the header value into a # Python tuple by including a comma in its definition. self.assertTrue(isinstance(accessControlExposeHeaders, str)) # Make sure we haven't accidentally left a comma space in the last # element of the Python header definition. self.assertFalse(accessControlExposeHeaders.endswith(', ')) actualHeaders = accessControlExposeHeaders.split(', ') for header in expectedHeaders: self.assertTrue(header.startswith('X-FluidDB-')) self.assertTrue(header in actualHeaders)
def testHeaderNotPresentWhenNoError(self): """ Check the WWW-Authenticate header is not present when we do not hit an error. """ payload = {'description': 'A new namespace', 'name': 'people'} content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders('Content-Length', [str(contentLength)]) request.requestHeaders.setRawHeaders('Content-Type', ['application/json']) request.requestHeaders.setRawHeaders('Host', ['fluiddb.fluidinfo.com']) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) # Check the WWW-Authenticate header is absent. headers = request.responseHeaders self.assertFalse(headers.hasHeader('WWW-Authenticate'))
def testCorsHeadersDoNotAppearForRegularRequests(self): """ Make sure CORS related headers do NOT appear in regular non-CORS requests """ payload = {'description': 'A namespace for tags I add to people', 'name': 'people'} content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders('Content-Length', [str(contentLength)]) request.requestHeaders.setRawHeaders('Content-Type', ['application/json']) request.requestHeaders.setRawHeaders('Host', ['fluiddb.fluidinfo.com']) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) # 201 Created self.assertEqual(request.code, http.CREATED) # check we don't have the CORS related headers headers = request.responseHeaders self.assertFalse(headers.hasHeader('Access-Control-Allow-Origin')) self.assertFalse( headers.hasHeader('Access-Control-Allow-Credentials')) self.assertFalse( headers.hasHeader('Access-Control-Expose-Headers'))
def testContentMD5DoesNotMatch(self): """ Checks that an incoming requests whose payload doesn't match the Content-MD5 header and returns a PRECONDITION FAILED (412). """ payload = {"description": "A namespace for tags that I'm using to" "add to people", "name": "people"} content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders("Content-MD5", ["bad-md5"]) request.requestHeaders.setRawHeaders("Content-Length", [str(contentLength)]) request.requestHeaders.setRawHeaders("Content-Type", ["application/json"]) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) self.assertEqual(request.code, http.PRECONDITION_FAILED)
def testContentMD5OK(self): """ Checks that an incoming requests whose payload matches the Content-MD5 header. """ payload = {"description": "A namespace for tags that I'm using to" " add to people", "name": "people"} content = json.dumps(payload) contentLength = len(content) md5Content = base64.standard_b64encode(md5(content).digest()) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders("Content-MD5", [md5Content]) request.requestHeaders.setRawHeaders("Content-Length", [str(contentLength)]) request.requestHeaders.setRawHeaders("Content-Type", ["application/json"]) request.requestHeaders.setRawHeaders("Host", ["fluiddb.fluidinfo.com"]) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) self.assertEqual(request.code, http.CREATED)
def testUnseekableContent(self): """ Test that sending a request whose content cannot have seek called on it without raising a ValueError gets a 400 Bad Request status, with the appropriate C{X-FluidDB-Error-Class} value in the header. """ request = FakeRequest('POST', 'namespaces/fluiddb') request.content = NoContent() resource = NamespacesResource(None, FakeSession()) resource.render(request) self.assertFalse(request.finished) self.assertEqual(request.status, http.BAD_REQUEST) self.assertEqual(request.getResponseHeader('X-FluidDB-Error-Class'), error.ContentSeekError.__name__)
def testHeaderPresentOn401Error(self): """ Check the WWW-Authenticate header is present, with the expected value when we hit a 401 (Unauthorized) error. """ class ExplodingPermissionDeniedFacade(object): """ A fake facade whose C{createNamespace} method always raises TPathPermissionDenied. """ def createNamespace(self, *args, **kwargs): """ Make something (unspecified) appear to go wrong with perms checking. @param args: Positional arguments for the new namespace. @param kwargs: Keyword arguments for the new namespace. @raise C{TPathPermissionDenied} no matter what. """ raise TPathPermissionDenied() payload = {'description': 'A new namespace', 'name': 'people'} content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders('Content-Length', [str(contentLength)]) request.requestHeaders.setRawHeaders('Content-Type', ['application/json']) request.requestHeaders.setRawHeaders('Host', ['fluiddb.fluidinfo.com']) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(ExplodingPermissionDeniedFacade(), FakeSession()) resource.render(request) # Check the response code and header content. self.assertEqual(request.code, http.UNAUTHORIZED) headers = request.responseHeaders self.assertTrue(headers.hasHeader('WWW-Authenticate')) self.assertEqual('Basic realm="Fluidinfo"', headers.getRawHeaders('WWW-Authenticate')[0])
def testInvalidCORSPreFlightRequestBadACRM(self): """ The request has an Origin header but the Access-Control-Request-Method header contains an invalid value so check it returns a regular OPTIONS response. """ # The origin to use in the tests dummyOrigin = 'http://foo.com' request = http.Request(DummyChannel(), False) request.method = 'OPTIONS' request.requestHeaders.setRawHeaders('Origin', [dummyOrigin]) request.requestHeaders.setRawHeaders( 'Access-Control-Request-Method', ['FOO']) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = NoContent() resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource._handleOptions(request, dummyOrigin) # 200 OK self.assertEqual(request.code, http.OK) # check we have the required headers headers = request.responseHeaders self.assertTrue(headers.hasHeader('Allow')) # Check the allowed methods (including and in addition to those # allowed for CORS) allowedMethods = headers.getRawHeaders('Allow')[0].split(', ') self.assertEqual( len(resource.allowedMethods), len(allowedMethods)) for item in resource.allowedMethods: self.assertTrue(item in allowedMethods) # There are *NO* CORS related headers self.assertFalse(headers.hasHeader('Access-Control-Allow-Origin')) self.assertFalse(headers.hasHeader('Access-Control-Max-Age')) self.assertFalse( headers.hasHeader('Access-Control-Allow-Credentials')) self.assertFalse(headers.hasHeader('Access-Control-Allow-Methods'))
def testNamespacesResource(self): resource = NamespacesResource(FakeFacadeClient(), FakeSession()) self._checkCORSPreFlightRequest(resource)
def testRegularCORSHeaders(self): """ Validates that the headers are handled correctly for a CORS request that doesn't use the OPTIONS verb """ # The origin to use in the tests dummyOrigin = 'http://foo.com' expectedHeaders = [ 'X-FluidDB-Error-Class', 'X-FluidDB-Path', 'X-FluidDB-Message', 'X-FluidDB-ObjectId', 'X-FluidDB-Name', 'X-FluidDB-Category', 'X-FluidDB-Action', 'X-FluidDB-Rangetype', 'X-FluidDB-Fieldname', 'X-FluidDB-Argument', 'X-FluidDB-Access-Token', 'X-FluidDB-Username', 'X-FluidDB-New-User' ] payload = {'description': 'A namespace for tags that I add to people', 'name': 'people'} content = json.dumps(payload) contentLength = len(content) request = http.Request(DummyChannel(), False) request.method = 'POST' request.requestHeaders.setRawHeaders('Content-Length', [str(contentLength)]) request.requestHeaders.setRawHeaders('Content-Type', ['application/json']) request.requestHeaders.setRawHeaders('Host', ['fluiddb.fluidinfo.com']) request.requestHeaders.setRawHeaders('Origin', [dummyOrigin]) request._fluidDB_reqid = 'xxx' request.args = dict() request.postpath = [] request.content = StringIO(content) resource = NamespacesResource(FakeFacadeClient(), FakeSession()) resource.render(request) # 201 Created self.assertEqual(request.code, http.CREATED) # check we have the required headers headers = request.responseHeaders self.assertTrue(headers.hasHeader('Access-Control-Allow-Origin')) self.assertTrue( headers.hasHeader('Access-Control-Allow-Credentials')) self.assertTrue( headers.hasHeader('Access-Control-Expose-Headers')) # check the values of the required headers self.assertEqual( dummyOrigin, headers.getRawHeaders('Access-Control-Allow-Origin')[0]) self.assertEqual( 'true', headers.getRawHeaders('Access-Control-Allow-Credentials')[0]) accessControlExposeHeaders = headers.getRawHeaders( 'Access-Control-Expose-Headers')[0] # Make sure we haven't accidentally turned the header value into a # Python tuple by including a comma in its definition. self.assertTrue(isinstance(accessControlExposeHeaders, str)) # Make sure we haven't accidentally left a comma space in the last # element of the Python header definition. self.assertFalse(accessControlExposeHeaders.endswith(', ')) actualHeaders = accessControlExposeHeaders.split(', ') for header in expectedHeaders: self.assertTrue(header.startswith('X-FluidDB-')) self.assertTrue(header in actualHeaders)