def test_http_timeout_option(self): good_values = ['1', '5.3', '10', '.001'] for val in good_values: middleware = s3token.filter_factory({ 'http_timeout': val, 'auth_uri': 'http://example.com', })(FakeApp()) self.assertEqual(float(val), middleware._timeout) bad_values = ['1, 4', '-3', '100', 'foo', '0'] for val in bad_values: with self.assertRaises(ValueError) as ctx: s3token.filter_factory({ 'http_timeout': val, 'auth_uri': 'http://example.com', })(FakeApp()) self.assertTrue(ctx.exception.args[0].startswith(( 'invalid literal for float():', 'could not convert string to float:', 'http_timeout must be between 0 and 60 seconds', )), 'Unexpected error message: %s' % ctx.exception) # default is 10 seconds middleware = s3token.filter_factory({ 'auth_uri': 'http://example.com'})(FakeApp()) self.assertEqual(10, middleware._timeout)
def test_insecure_option(self): # insecure is passed as a string. # Some non-secure values. true_values = ['true', 'True', '1', 'yes'] for val in true_values: config = {'insecure': val, 'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3token.filter_factory(config)(self.app) self.assertIs(False, middleware._verify) # Some "secure" values, including unexpected value. false_values = ['false', 'False', '0', 'no', 'someweirdvalue'] for val in false_values: config = {'insecure': val, 'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3token.filter_factory(config)(self.app) self.assertEqual('false_ind', middleware._verify) # Default is secure. config = {'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3token.filter_factory(config)(self.app) self.assertIs('false_ind', middleware._verify)
def test_http_timeout_option(self): good_values = ['1', '5.3', '10', '.001'] for val in good_values: middleware = s3token.filter_factory({ 'http_timeout': val, 'auth_uri': 'http://example.com', })(FakeApp()) self.assertEqual(float(val), middleware._timeout) bad_values = ['1, 4', '-3', '100', 'foo', '0'] for val in bad_values: with self.assertRaises(ValueError) as ctx: s3token.filter_factory({ 'http_timeout': val, 'auth_uri': 'http://example.com', })(FakeApp()) self.assertTrue(ctx.exception.args[0].startswith(( 'invalid literal for float():', 'could not convert string to float:', 'http_timeout must be between 0 and 60 seconds', )), 'Unexpected error message: %s' % ctx.exception) # default is 10 seconds middleware = s3token.filter_factory({ 'auth_uri': 'http://example.com'})(FakeApp()) self.assertEqual(10, middleware._timeout)
def test_insecure_option(self): # insecure is passed as a string. # Some non-secure values. true_values = ['true', 'True', '1', 'yes'] for val in true_values: config = {'insecure': val, 'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3token.filter_factory(config)(self.app) self.assertIs(False, middleware._verify) # Some "secure" values, including unexpected value. false_values = ['false', 'False', '0', 'no', 'someweirdvalue'] for val in false_values: config = {'insecure': val, 'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3token.filter_factory(config)(self.app) self.assertEqual('false_ind', middleware._verify) # Default is secure. config = {'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3token.filter_factory(config)(self.app) self.assertIs('false_ind', middleware._verify)
def test_auth_uris(self): for conf, expected in [ ({'auth_uri': 'https://example.com/v2.0'}, 'https://example.com/v2.0/s3tokens'), # Trailing slash doesn't interfere ({'auth_uri': 'https://example.com/v2.0/'}, 'https://example.com/v2.0/s3tokens'), # keystone running under mod_wsgi often has a path prefix ({'auth_uri': 'https://example.com/identity/v2.0'}, 'https://example.com/identity/v2.0/s3tokens'), ({'auth_uri': 'https://example.com/identity/v2.0/'}, 'https://example.com/identity/v2.0/s3tokens'), # IPv4 addresses are fine ({'auth_uri': 'http://127.0.0.1:35357/v3'}, 'http://127.0.0.1:35357/v3/s3tokens'), ({'auth_uri': 'http://127.0.0.1:35357/v3/'}, 'http://127.0.0.1:35357/v3/s3tokens'), # IPv6 addresses need [brackets] per RFC 3986 ({'auth_uri': 'https://[::FFFF:129.144.52.38]:5000/v3'}, 'https://[::FFFF:129.144.52.38]:5000/v3/s3tokens'), ({'auth_uri': 'https://[::FFFF:129.144.52.38]:5000/v3/'}, 'https://[::FFFF:129.144.52.38]:5000/v3/s3tokens'), ]: middleware = s3token.filter_factory(conf)(self.app) self.assertEqual(expected, middleware._request_uri)
def test_http_timeout(self, MOCK_REQUEST): self.middleware = s3token.filter_factory({ 'http_timeout': '2', 'auth_uri': 'http://example.com', })(FakeApp()) MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': json.dumps(GOOD_RESPONSE_V2) }) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self.assertTrue(MOCK_REQUEST.called) mock_args, mock_kwargs = MOCK_REQUEST.call_args self.assertEqual(mock_kwargs['timeout'], 2)
def test_insecure(self, MOCK_REQUEST): self.middleware = s3token.filter_factory({ 'insecure': 'True', 'auth_uri': 'http://example.com' })(self.app) text_return_value = json.dumps(GOOD_RESPONSE_V2) MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': text_return_value }) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self.assertTrue(MOCK_REQUEST.called) mock_args, mock_kwargs = MOCK_REQUEST.call_args self.assertIs(mock_kwargs['verify'], False)
def test_auth_uris(self): for conf, expected in [ ({'auth_uri': 'https://example.com/v2.0'}, 'https://example.com/v2.0/s3tokens'), # Trailing slash doesn't interfere ({'auth_uri': 'https://example.com/v2.0/'}, 'https://example.com/v2.0/s3tokens'), # keystone running under mod_wsgi often has a path prefix ({'auth_uri': 'https://example.com/identity/v2.0'}, 'https://example.com/identity/v2.0/s3tokens'), ({'auth_uri': 'https://example.com/identity/v2.0/'}, 'https://example.com/identity/v2.0/s3tokens'), # IPv4 addresses are fine ({'auth_uri': 'http://127.0.0.1:35357/v3'}, 'http://127.0.0.1:35357/v3/s3tokens'), ({'auth_uri': 'http://127.0.0.1:35357/v3/'}, 'http://127.0.0.1:35357/v3/s3tokens'), # IPv6 addresses need [brackets] per RFC 3986 ({'auth_uri': 'https://[::FFFF:129.144.52.38]:5000/v3'}, 'https://[::FFFF:129.144.52.38]:5000/v3/s3tokens'), ({'auth_uri': 'https://[::FFFF:129.144.52.38]:5000/v3/'}, 'https://[::FFFF:129.144.52.38]:5000/v3/s3tokens'), ]: middleware = s3token.filter_factory(conf)(self.app) self.assertEqual(expected, middleware._request_uri)
def test_secret_is_cached(self, MOCK_REQUEST, MOCK_KEYSTONE, MOCK_CACHE_FROM_ENV): self.middleware = s3token.filter_factory({ 'auth_uri': 'http://example.com', 'secret_cache_duration': '20', 'auth_type': 'v3password', 'auth_url': 'http://example.com:5000/v3', 'username': '******', 'password': '******', 'project_name': 'service', 'user_domain_name': 'default', 'project_domain_name': 'default', })(FakeApp()) self.assertEqual(20, self.middleware._secret_cache_duration) cache = MOCK_CACHE_FROM_ENV.return_value fake_cache_response = ({}, 'token_id', {'id': 'tenant_id'}, 'secret') cache.get.return_value = fake_cache_response MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': json.dumps(GOOD_RESPONSE_V2)}) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', 'check_signature': lambda x: True } req.get_response(self.middleware) # Ensure we don't request auth from keystone self.assertFalse(MOCK_REQUEST.called)
def test_authorized_trailing_slash(self): self.middleware = s3token.filter_factory({ 'auth_uri': self.TEST_AUTH_URI + '/'})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self._assert_authorized(req)
def test_authorized_trailing_slash(self): self.middleware = s3token.filter_factory({ 'auth_uri': self.TEST_AUTH_URI + '/'})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self._assert_authorized(req)
def test_secret_sets_cache(self, MOCK_REQUEST, MOCK_KEYSTONE, MOCK_CACHE_FROM_ENV): self.middleware = s3token.filter_factory({ 'auth_uri': 'http://example.com', 'secret_cache_duration': '20', 'auth_type': 'v3password', 'auth_url': 'http://example.com:5000/v3', 'username': '******', 'password': '******', 'project_name': 'service', 'user_domain_name': 'default', 'project_domain_name': 'default', })(FakeApp()) self.assertEqual(20, self.middleware._secret_cache_duration) cache = MOCK_CACHE_FROM_ENV.return_value cache.get.return_value = None keystone_client = MOCK_KEYSTONE.return_value keystone_client.ec2.get.return_value = mock.Mock(secret='secret') MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': json.dumps(GOOD_RESPONSE_V2)}) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', 'check_signature': lambda x: True } req.get_response(self.middleware) expected_headers = { 'X-Identity-Status': u'Confirmed', 'X-Roles': u'swift-user,_member_', 'X-User-Id': u'USER_ID', 'X-User-Name': u'S3_USER', 'X-Tenant-Id': u'TENANT_ID', 'X-Tenant-Name': u'TENANT_NAME', 'X-Project-Id': u'TENANT_ID', 'X-Project-Name': u'TENANT_NAME', } self.assertTrue(MOCK_REQUEST.called) tenant = GOOD_RESPONSE_V2['access']['token']['tenant'] token = GOOD_RESPONSE_V2['access']['token']['id'] expected_cache = (expected_headers, token, tenant, 'secret') cache.set.assert_called_once_with('s3secret/access', expected_cache, time=20)
def test_authorized_v3(self): auth_uri = 'http://fakehost:35357/v3/' self.requests_mock.post( auth_uri + 's3tokens', status_code=201, json=GOOD_RESPONSE_V3) self.middleware = s3token.filter_factory({ 'auth_uri': auth_uri})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self._assert_authorized(req)
def test_authorized_v3(self): auth_uri = 'http://fakehost:35357/v3/' self.requests_mock.post( auth_uri + 's3tokens', status_code=201, json=GOOD_RESPONSE_V3) self.middleware = s3token.filter_factory({ 'auth_uri': auth_uri})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self._assert_authorized(req)
def test_authorized_http(self): # Following https://github.com/openstack/keystone/commit/3ec1aa4 # even v2 URLs would respond with a v3-format response auth_uri = 'http://fakehost:35357/v2.0/' self.requests_mock.post( auth_uri + 's3tokens', status_code=201, json=GOOD_RESPONSE_V3) self.middleware = s3token.filter_factory({ 'auth_uri': auth_uri})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self._assert_authorized(req)
def test_authorized_http(self): # Following https://github.com/openstack/keystone/commit/3ec1aa4 # even v2 URLs would respond with a v3-format response auth_uri = 'http://fakehost:35357/v2.0/' self.requests_mock.post( auth_uri + 's3tokens', status_code=201, json=GOOD_RESPONSE_V3) self.middleware = s3token.filter_factory({ 'auth_uri': auth_uri})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self._assert_authorized(req)
def test_insecure(self, MOCK_REQUEST): self.middleware = s3token.filter_factory( {'insecure': 'True', 'auth_uri': 'http://example.com'})(self.app) text_return_value = json.dumps(GOOD_RESPONSE_V2) MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': text_return_value}) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self.assertTrue(MOCK_REQUEST.called) mock_args, mock_kwargs = MOCK_REQUEST.call_args self.assertIs(mock_kwargs['verify'], False)
def test_http_timeout(self, MOCK_REQUEST): self.middleware = s3token.filter_factory({ 'http_timeout': '2', 'auth_uri': 'http://example.com', })(FakeApp()) MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': json.dumps(GOOD_RESPONSE_V2)}) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['s3api.auth_details'] = { 'access_key': u'access', 'signature': u'signature', 'string_to_sign': u'token', } req.get_response(self.middleware) self.assertTrue(MOCK_REQUEST.called) mock_args, mock_kwargs = MOCK_REQUEST.call_args self.assertEqual(mock_kwargs['timeout'], 2)
def test_bad_auth_uris(self): for auth_uri in ['/not/a/uri', 'http://', '//example.com/path']: with self.assertRaises(ConfigFileError) as cm: s3token.filter_factory({'auth_uri': auth_uri})(self.app) self.assertEqual('Invalid auth_uri; must include scheme and host', cm.exception.args[0]) with self.assertRaises(ConfigFileError) as cm: s3token.filter_factory({'auth_uri': 'nonhttp://example.com'})(self.app) self.assertEqual('Invalid auth_uri; scheme must be http or https', cm.exception.args[0]) for auth_uri in [ 'http://[email protected]/', 'http://example.com/?with=query', 'http://example.com/#with-fragment' ]: with self.assertRaises(ConfigFileError) as cm: s3token.filter_factory({'auth_uri': auth_uri})(self.app) self.assertEqual( 'Invalid auth_uri; must not include username, ' 'query, or fragment', cm.exception.args[0])
def test_bad_auth_uris(self): for auth_uri in [ '/not/a/uri', 'http://', '//example.com/path']: with self.assertRaises(ConfigFileError) as cm: s3token.filter_factory({'auth_uri': auth_uri})(self.app) self.assertEqual('Invalid auth_uri; must include scheme and host', cm.exception.message) with self.assertRaises(ConfigFileError) as cm: s3token.filter_factory({ 'auth_uri': 'nonhttp://example.com'})(self.app) self.assertEqual('Invalid auth_uri; scheme must be http or https', cm.exception.message) for auth_uri in [ 'http://[email protected]/', 'http://example.com/?with=query', 'http://example.com/#with-fragment']: with self.assertRaises(ConfigFileError) as cm: s3token.filter_factory({'auth_uri': auth_uri})(self.app) self.assertEqual('Invalid auth_uri; must not include username, ' 'query, or fragment', cm.exception.message)
def do_test(conf, expected): conf.update(self.conf) middleware = s3token.filter_factory(conf)(self.app) self.assertEqual(expected, middleware._reseller_prefix)