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 = s3_token.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 = s3_token.filter_factory(config)(self.app) self.assertEqual('false_ind', middleware._verify) # Default is secure. config = {'certfile': 'false_ind', 'auth_uri': 'http://example.com'} middleware = s3_token.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 = s3_token.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: s3_token.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 = s3_token.filter_factory({ 'auth_uri': 'http://example.com'})(FakeApp()) self.assertEqual(10, middleware._timeout)
def test_http_timeout(self, MOCK_REQUEST): self.middleware = s3_token.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['swift3.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_auth_version(self): for conf, expected in [ # if provided just host/scheme, tack on the default # version/endpoint like before ({ 'auth_uri': 'https://example.com' }, 'https://example.com/v2.0/s3tokens'), # if provided a version-specific URI, trust it ({ 'auth_uri': 'https://example.com:5000', 'auth_version': '2.0' }, 'https://example.com:5000/v2.0/s3tokens'), ({ 'auth_uri': 'http://example.com', 'auth_version': '3' }, 'http://example.com/v3/s3tokens'), # even try to allow for future versions ({ 'auth_uri': 'http://example.com', 'auth_version': '4.25' }, 'http://example.com/v4.25/s3tokens'), # keystone running under mod_wsgi often has a path prefix ({ 'auth_uri': 'https://example.com/identity' }, 'https://example.com/identity/v2.0/s3tokens'), # doesn't really work to include version in auth_uri ({ 'auth_uri': 'https://example.com/v2.0' }, 'https://example.com/v2.0/v2.0/s3tokens') ]: middleware = s3_token.filter_factory(conf)(self.app) self.assertEqual(expected, middleware._request_uri)
def test_insecure(self, MOCK_REQUEST): self.middleware = s3_token.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['swift3.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_authorized_trailing_slash(self): self.middleware = s3_token.filter_factory({ 'auth_uri': self.TEST_AUTH_URI + '/'})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.headers['Authorization'] = 'AWS access:signature' req.headers['X-Storage-Token'] = 'token' req.get_response(self.middleware) self._assert_authorized(req)
def test_authorized_trailing_slash(self): self.middleware = s3_token.filter_factory({ 'auth_uri': self.TEST_AUTH_URI + '/'})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.headers['Authorization'] = 'AWS access:signature' req.headers['X-Storage-Token'] = 'token' req.get_response(self.middleware) self.assertTrue(req.path.startswith('/v1/AUTH_TENANT_ID')) self.assertEqual(req.headers['X-Auth-Token'], 'TOKEN_ID')
def test_authorized_trailing_slash(self): self.middleware = s3_token.filter_factory({ 'auth_uri': self.TEST_AUTH_URI + '/'})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['swift3.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 = s3_token.filter_factory( {'auth_uri': self.TEST_AUTH_URI + '/'})(self.app) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['swift3.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_ipv6_auth_host_option(self): config = {} ipv6_addr = '::FFFF:129.144.52.38' identity_uri = 'https://[::FFFF:129.144.52.38]:35357' # Raw IPv6 address should work config['auth_host'] = ipv6_addr middleware = s3_token.filter_factory(config)(self.app) self.assertEqual(identity_uri, middleware._request_uri) # ...as should workarounds already in use config['auth_host'] = '[%s]' % ipv6_addr middleware = s3_token.filter_factory(config)(self.app) self.assertEqual(identity_uri, middleware._request_uri) # ... with no config, we should get config error del config['auth_host'] with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory(config)(self.app) self.assertEqual('Either auth_uri or auth_host required', cm.exception.message)
def test_bad_auth_parts(self): with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory({ 'auth_host': 'example.com', 'auth_protocol': '' })(self.app) self.assertEqual('Invalid auth_uri; must include scheme and host', cm.exception.message) with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory({ 'auth_host': 'example.com', 'auth_protocol': 'ftp' })(self.app) self.assertEqual('Invalid auth_uri; scheme must be http or https', cm.exception.message) for conf in [{ 'auth_host': 'example.com/?with=query' }, { 'auth_host': 'user:[email protected]' }, { 'auth_host': 'example.com/#with-fragment' }]: with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory(conf)(self.app) self.assertEqual( 'Invalid auth_uri; must not include username, ' 'query, or fragment', cm.exception.message)
def test_authorized_http(self): protocol = 'http' host = 'fakehost' port = 35357 self.requests_mock.post( '%s://%s:%s/v2.0/s3tokens' % (protocol, host, port), status_code=201, json=GOOD_RESPONSE) self.middleware = ( s3_token.filter_factory({'auth_protocol': 'http', 'auth_host': host, 'auth_port': port})(self.app)) req = Request.blank('/v1/AUTH_cfa/c/o') req.headers['Authorization'] = 'AWS access:signature' req.headers['X-Storage-Token'] = 'token' req.get_response(self.middleware) self._assert_authorized(req)
def test_secret_is_cached(self, MOCK_REQUEST, MOCK_KEYSTONE, MOCK_CACHE_FROM_ENV): self.middleware = s3_token.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['swift3.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_insecure(self, MOCK_REQUEST): self.middleware = s3_token.filter_factory( {'insecure': 'True', 'auth_uri': 'http://example.com'})(self.app) text_return_value = json.dumps(GOOD_RESPONSE) MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': text_return_value}) req = Request.blank('/v1/AUTH_cfa/c/o') req.headers['Authorization'] = 'AWS access:signature' req.headers['X-Storage-Token'] = '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 = s3_token.filter_factory({ 'http_timeout': '2', 'auth_uri': 'http://example.com', })(FakeApp()) MOCK_REQUEST.return_value = TestResponse({ 'status_code': 201, 'text': json.dumps(GOOD_RESPONSE)}) req = Request.blank('/v1/AUTH_cfa/c/o') req.headers['Authorization'] = 'AWS access:signature' req.headers['X-Storage-Token'] = '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 = s3_token.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['swift3.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_authorized_http(self): protocol = 'http' host = 'fakehost' port = 35357 self.requests_mock.post( '%s://%s:%s/v2.0/s3tokens' % (protocol, host, port), status_code=201, json=GOOD_RESPONSE_V3) self.middleware = ( s3_token.filter_factory({'auth_protocol': 'http', 'auth_host': host, 'auth_port': port})(self.app)) req = Request.blank('/v1/AUTH_cfa/c/o') req.environ['swift3.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_http_timeout(self, MOCK_REQUEST): self.middleware = s3_token.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['swift3.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_auth_version(self): for conf, expected in [ # if provided just host/scheme, tack on the default # version/endpoint like before ({'auth_uri': 'https://example.com'}, 'https://example.com/v2.0/s3tokens'), # if provided a version-specific URI, trust it ({'auth_uri': 'https://example.com:5000', 'auth_version': '2.0'}, 'https://example.com:5000/v2.0/s3tokens'), ({'auth_uri': 'http://example.com', 'auth_version': '3'}, 'http://example.com/v3/s3tokens'), # even try to allow for future versions ({'auth_uri': 'http://example.com', 'auth_version': '4.25'}, 'http://example.com/v4.25/s3tokens'), # keystone running under mod_wsgi often has a path prefix ({'auth_uri': 'https://example.com/identity'}, 'https://example.com/identity/v2.0/s3tokens'), # doesn't really work to include version in auth_uri ({'auth_uri': 'https://example.com/v2.0'}, 'https://example.com/v2.0/v2.0/s3tokens')]: middleware = s3_token.filter_factory(conf)(self.app) self.assertEqual(expected, middleware._request_uri)
def test_bad_auth_parts(self): with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory({ 'auth_host': 'example.com', 'auth_protocol': ''})(self.app) self.assertEqual('Invalid auth_uri; must include scheme and host', cm.exception.message) with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory({ 'auth_host': 'example.com', 'auth_protocol': 'ftp'})(self.app) self.assertEqual('Invalid auth_uri; scheme must be http or https', cm.exception.message) for conf in [ {'auth_host': 'example.com/?with=query'}, {'auth_host': 'user:[email protected]'}, {'auth_host': 'example.com/#with-fragment'}]: with self.assertRaises(ConfigFileError) as cm: s3_token.filter_factory(conf)(self.app) self.assertEqual('Invalid auth_uri; must not include username, ' 'query, or fragment', cm.exception.message)
def test_bad_auth_uris(self): for auth_uri in ['/not/a/uri', 'http://', '//example.com/path']: with self.assertRaises(ConfigFileError) as cm: s3_token.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: s3_token.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: s3_token.filter_factory({'auth_uri': auth_uri})(self.app) self.assertEqual( 'Invalid auth_uri; must not include username, ' 'query, or fragment', cm.exception.message)
def test_bad_auth_uris(self): for auth_uri in [ '/not/a/uri', 'http://', '//example.com/path']: with self.assertRaises(ConfigFileError) as cm: s3_token.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: s3_token.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: s3_token.filter_factory({'auth_uri': auth_uri})(self.app) self.assertEqual('Invalid auth_uri; must not include username, ' 'query, or fragment', cm.exception.message)
def test_secret_sets_cache(self, MOCK_REQUEST, MOCK_KEYSTONE, MOCK_CACHE_FROM_ENV): self.middleware = s3_token.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['swift3.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)