Merge "proxy-logging: create field for access_user_id"
This commit is contained in:
@@ -471,7 +471,8 @@ class TestS3ApiBucketNoACL(BaseS3ApiBucket, S3ApiTestCase):
|
||||
self.assertEqual(1, len(access_lines))
|
||||
parts = access_lines[0].split()
|
||||
self.assertEqual(' '.join(parts[3:7]), 'HEAD /junk HTTP/1.0 200')
|
||||
self.assertEqual(parts[-1], str(bucket_policy_index))
|
||||
self.assertEqual(parts[-2], str(bucket_policy_index))
|
||||
self.assertEqual(parts[-1], 'test:tester') # access_user_id
|
||||
|
||||
def test_bucket_HEAD_policy_index_logging(self):
|
||||
self._do_test_bucket_HEAD_policy_index_logging(0)
|
||||
@@ -1494,9 +1495,16 @@ class TestS3ApiBucketNoACL(BaseS3ApiBucket, S3ApiTestCase):
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers=headers,
|
||||
body=req_body)
|
||||
|
||||
# Test V4 bucket creation and access_user_id setting
|
||||
status, headers, body = self.call_s3api(req)
|
||||
self.assertEqual(status.split()[0], '200', body)
|
||||
|
||||
# Verify access_user_id is set correctly in environ for V4 bucket
|
||||
# creation
|
||||
self.assertEqual(req.environ['swift.access_logging']['user_id'],
|
||||
'test:tester')
|
||||
|
||||
def test_bucket_PUT_v4_with_body_bad_hash(self):
|
||||
elem = Element('CreateBucketConfiguration')
|
||||
SubElement(elem, 'LocationConstraint').text = self.s3api.conf.location
|
||||
|
||||
@@ -84,7 +84,10 @@ class BaseS3ApiObj(object):
|
||||
environ={'REQUEST_METHOD': method},
|
||||
headers={'Authorization': 'AWS test:tester:hmac',
|
||||
'Date': self.get_date_header()})
|
||||
self.assertNotIn('swift.access_logging', req.environ)
|
||||
status, headers, body = self.call_s3api(req)
|
||||
self.assertEqual(req.environ['swift.access_logging'],
|
||||
{'user_id': 'test:tester'})
|
||||
self.assertEqual(status.split()[0], '200')
|
||||
# we'll want this for logging
|
||||
self._assert_policy_index(req.headers, headers,
|
||||
@@ -204,7 +207,8 @@ class BaseS3ApiObj(object):
|
||||
parts = access_lines[0].split()
|
||||
self.assertEqual(' '.join(parts[3:7]),
|
||||
'GET /bucket/object HTTP/1.0 200')
|
||||
self.assertEqual(parts[-1], str(bucket_policy_index))
|
||||
self.assertEqual(parts[-2], str(bucket_policy_index))
|
||||
self.assertEqual(parts[-1], 'test:tester') # access_user_id
|
||||
|
||||
def _test_object_HEAD_Range(self, range_value):
|
||||
req = Request.blank('/bucket/object',
|
||||
@@ -784,6 +788,8 @@ class BaseS3ApiObj(object):
|
||||
body=self.object_body)
|
||||
req.date = datetime.now()
|
||||
req.content_type = 'text/plain'
|
||||
|
||||
# Test V4 signature processing and access_user_id setting
|
||||
status, headers, body = self.call_s3api(req)
|
||||
self.assertEqual(status.split()[0], '200')
|
||||
# Check that s3api returns an etag header.
|
||||
@@ -796,6 +802,10 @@ class BaseS3ApiObj(object):
|
||||
self.assertEqual('/v1/AUTH_test/bucket/object',
|
||||
req.environ.get('swift.backend_path'))
|
||||
|
||||
# Verify access_user_id is set correctly in environ for V4 signature
|
||||
self.assertEqual(req.environ['swift.access_logging']['user_id'],
|
||||
'test:tester')
|
||||
|
||||
def test_object_PUT_v4_bad_hash(self):
|
||||
orig_app = self.s3api.app
|
||||
|
||||
@@ -826,7 +836,10 @@ class BaseS3ApiObj(object):
|
||||
body=self.object_body)
|
||||
req.date = datetime.now()
|
||||
req.content_type = 'text/plain'
|
||||
self.assertNotIn('swift.access_logging', req.environ)
|
||||
status, headers, body = self.call_s3api(req)
|
||||
self.assertEqual(req.environ['swift.access_logging'],
|
||||
{'user_id': 'test:tester'})
|
||||
self.assertEqual(status.split()[0], '400')
|
||||
self.assertEqual(self._get_error_code(body),
|
||||
'XAmzContentSHA256Mismatch')
|
||||
@@ -877,6 +890,9 @@ class BaseS3ApiObj(object):
|
||||
body=self.object_body)
|
||||
req.date = datetime.now()
|
||||
req.content_type = 'text/plain'
|
||||
|
||||
# Test V4 UNSIGNED-PAYLOAD signature processing and access_user_id
|
||||
# setting
|
||||
status, headers, body = self.call_s3api(req)
|
||||
self.assertEqual(status.split()[0], '200')
|
||||
# Check that s3api returns an etag header.
|
||||
@@ -889,6 +905,11 @@ class BaseS3ApiObj(object):
|
||||
self.assertIn(b'UNSIGNED-PAYLOAD', SigV4Request(
|
||||
req.environ, self.s3api.conf)._canonical_request())
|
||||
|
||||
# Verify access_user_id is set correctly in environ for V4
|
||||
# UNSIGNED-PAYLOAD
|
||||
self.assertEqual(req.environ['swift.access_logging']['user_id'],
|
||||
'test:tester')
|
||||
|
||||
def _test_object_PUT_copy(self, head_resp, put_header=None,
|
||||
src_path='/some/source', timestamp=None):
|
||||
account = 'test:tester'
|
||||
|
||||
@@ -536,7 +536,11 @@ class TestS3ApiMiddleware(S3ApiTestCase):
|
||||
headers={'Date': self.get_date_header()},
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
req.content_type = 'text/plain'
|
||||
status, headers, body = self.call_s3api(req)
|
||||
|
||||
# Test with ProxyLoggingMiddleware for access_user_id logging for
|
||||
# presigned URLs
|
||||
app = ProxyLoggingMiddleware(self.s3api, {}, logger=self.logger)
|
||||
status, headers, body = self.call_app(req, app=app)
|
||||
self.assertIn('swift.backend_path', req.environ)
|
||||
self.assertEqual('/v1/AUTH_test/bucket/object',
|
||||
req.environ['swift.backend_path'])
|
||||
@@ -545,6 +549,16 @@ class TestS3ApiMiddleware(S3ApiTestCase):
|
||||
self.assertNotIn('Authorization', headers)
|
||||
self.assertNotIn('X-Auth-Token', headers)
|
||||
|
||||
# Verify access_user_id is logged correctly for V4 presigned URLs
|
||||
access_lines = self.logger.get_lines_for_level('info')
|
||||
self.assertEqual(1, len(access_lines))
|
||||
parts = access_lines[0].split()
|
||||
# For presigned URLs, the logged path includes query parameters
|
||||
self.assertTrue(' '.join(parts[3:6]).startswith('GET /bucket/object'))
|
||||
self.assertEqual(parts[5], 'HTTP/1.0')
|
||||
self.assertEqual(parts[6], '200')
|
||||
self.assertEqual(parts[-1], 'test:tester') # access_user_id
|
||||
|
||||
def test_signed_urls_v4_bad_credential(self):
|
||||
def test(credential, message, extra=b''):
|
||||
req = Request.blank(
|
||||
@@ -1134,7 +1148,10 @@ class TestS3ApiMiddleware(S3ApiTestCase):
|
||||
'X-Amz-Content-SHA256': '0' * 64}
|
||||
req = Request.blank('/bucket/object', environ=environ, headers=headers)
|
||||
req.content_type = 'text/plain'
|
||||
status, headers, body = self.call_s3api(req)
|
||||
|
||||
# Test with ProxyLoggingMiddleware to verify access_user_id logging
|
||||
app = ProxyLoggingMiddleware(self.s3api, {}, logger=self.logger)
|
||||
status, headers, body = self.call_app(req, app=app)
|
||||
self.assertEqual(status.split()[0], '200', body)
|
||||
self.assertIn('swift.backend_path', req.environ)
|
||||
self.assertEqual('/v1/AUTH_test/bucket/object',
|
||||
@@ -1143,6 +1160,14 @@ class TestS3ApiMiddleware(S3ApiTestCase):
|
||||
self.assertEqual(authz_header, headers['Authorization'])
|
||||
self.assertNotIn('X-Auth-Token', headers)
|
||||
|
||||
# Verify access_user_id is logged correctly for V4 signature
|
||||
access_lines = self.logger.get_lines_for_level('info')
|
||||
self.assertEqual(1, len(access_lines))
|
||||
parts = access_lines[0].split()
|
||||
self.assertEqual(' '.join(parts[3:7]),
|
||||
'GET /bucket/object HTTP/1.0 200')
|
||||
self.assertEqual(parts[-1], 'test:tester') # access_user_id
|
||||
|
||||
def test_signature_v4_no_date(self):
|
||||
environ = {
|
||||
'REQUEST_METHOD': 'GET'}
|
||||
@@ -1752,7 +1777,9 @@ class TestS3ApiMiddleware(S3ApiTestCase):
|
||||
req.content_type = 'text/plain'
|
||||
log_conf = {'log_msg_template': '{method} {path} {log_info}'}
|
||||
app = ProxyLoggingMiddleware(self.s3api, log_conf, self.logger)
|
||||
self.assertNotIn('swift.access_logging', req.environ)
|
||||
status, headers, body = self.call_app(req, app=app)
|
||||
self.assertNotIn('swift.access_logging', req.environ)
|
||||
|
||||
self.assertEqual(
|
||||
['403.AccessDenied.invalid_credential'],
|
||||
@@ -1763,6 +1790,32 @@ class TestS3ApiMiddleware(S3ApiTestCase):
|
||||
['HEAD /bucket/object s3:err:AccessDenied.invalid_credential'],
|
||||
self.logger.get_lines_for_level('info'))
|
||||
|
||||
def test_access_user_id_logging(self):
|
||||
# verify that proxy logging gets access_user_id from S3 requests
|
||||
environ = {'REQUEST_METHOD': 'GET'}
|
||||
headers = {
|
||||
'Authorization': 'AWS test:tester:hmac',
|
||||
'Date': self.get_date_header()}
|
||||
req = Request.blank('/bucket/object', environ=environ,
|
||||
headers=headers)
|
||||
|
||||
# Use a log template that includes access_user_id
|
||||
log_conf = {
|
||||
'log_msg_template':
|
||||
'{method} {path} {account} {container} {object} '
|
||||
'{status_int} {access_user_id}'
|
||||
}
|
||||
app = ProxyLoggingMiddleware(self.s3api, log_conf, self.logger)
|
||||
status, headers, body = self.call_app(req, app=app)
|
||||
|
||||
# Should be successful GET
|
||||
self.assertEqual(status.split()[0], '200')
|
||||
# Verify the access_user_id is logged correctly
|
||||
expected_log = ('GET /bucket/object AUTH_test bucket object '
|
||||
'200 test:tester')
|
||||
self.assertEqual([expected_log],
|
||||
self.logger.get_lines_for_level('info'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1906,7 +1906,7 @@ class TestProxyLogging(unittest.TestCase):
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = b''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEqual(len(log_parts), 21)
|
||||
self.assertEqual(len(log_parts), 22)
|
||||
self.assertEqual(log_parts[0], '-')
|
||||
self.assertEqual(log_parts[1], '-')
|
||||
self.assertEqual(log_parts[2], '26/Apr/1970/17/46/41')
|
||||
@@ -1929,6 +1929,7 @@ class TestProxyLogging(unittest.TestCase):
|
||||
self.assertEqual(log_parts[18], '10000000.000000000')
|
||||
self.assertEqual(log_parts[19], '10000001.000000000')
|
||||
self.assertEqual(log_parts[20], '-')
|
||||
self.assertEqual(log_parts[21], '-')
|
||||
|
||||
def test_dual_logging_middlewares(self):
|
||||
# Since no internal request is being made, outer most proxy logging
|
||||
@@ -2148,3 +2149,43 @@ class TestProxyLogging(unittest.TestCase):
|
||||
obscured_test(params, headers, ['param_two', 'param_one'],
|
||||
['X-Auth-Token', 'X-Other-Header'],
|
||||
expected_params, expected_headers)
|
||||
|
||||
def test_access_user_id_field(self):
|
||||
"""Test that access_user_id field is logged correctly."""
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {})
|
||||
app.access_logger = debug_logger()
|
||||
req = Request.blank('/', environ={
|
||||
'REQUEST_METHOD': 'GET',
|
||||
'swift.access_logging': {'user_id': 'test:tester'},
|
||||
})
|
||||
resp = app(req.environ, start_response)
|
||||
b''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEqual(log_parts[21], 'test:tester')
|
||||
|
||||
# test that user_id is not logged if it is not present
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {})
|
||||
app.access_logger = debug_logger()
|
||||
req = Request.blank('/', environ={
|
||||
'REQUEST_METHOD': 'GET',
|
||||
})
|
||||
resp = app(req.environ, start_response)
|
||||
b''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEqual(log_parts[21], '-')
|
||||
|
||||
def test_access_user_id_field_with_anonymization(self):
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {
|
||||
'log_anonymization_salt': 'secret_salt',
|
||||
'log_msg_template': '{method} {path} {access_user_id.anonymized}'
|
||||
})
|
||||
app.access_logger = debug_logger()
|
||||
req = Request.blank('/', environ={
|
||||
'REQUEST_METHOD': 'GET',
|
||||
'swift.access_logging': {'user_id': 'test:tester'},
|
||||
})
|
||||
resp = app(req.environ, start_response)
|
||||
b''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEqual(log_parts[-1],
|
||||
'{SMD5}14fe1612c332096e282486e4baa37e63')
|
||||
|
||||
@@ -645,6 +645,20 @@ class TestAuth(unittest.TestCase):
|
||||
auth.DEFAULT_TOKEN_LIFE - 0.5, delta=0.5)
|
||||
self.assertGreater(len(resp.headers['x-auth-token']), 10)
|
||||
|
||||
def test_get_token_sets_access_logging_user_id(self):
|
||||
# Test that token generation sets access logging user_id
|
||||
test_auth = auth.filter_factory({'user_ac_user': 'testing'})(FakeApp())
|
||||
req = self._make_request(
|
||||
'/auth/v1.0',
|
||||
headers={'X-Auth-User': 'ac:user', 'X-Auth-Key': 'testing'})
|
||||
resp = req.get_response(test_auth)
|
||||
self.assertEqual(resp.status_int, 200)
|
||||
# Check that access logging user_id was set during token generation
|
||||
self.assertIn('swift.access_logging', req.environ)
|
||||
self.assertIn('user_id', req.environ['swift.access_logging'])
|
||||
self.assertEqual(req.environ['swift.access_logging']['user_id'],
|
||||
'ac:user')
|
||||
|
||||
def test_get_token_memcache_error(self):
|
||||
test_auth = auth.filter_factory({'user_ac_user': 'testing'})(FakeApp())
|
||||
req = self._make_request(
|
||||
@@ -1135,7 +1149,10 @@ class TestAuth(unittest.TestCase):
|
||||
req = self._make_request(
|
||||
quoted_acct, headers={'X-Auth-Token': auth_token})
|
||||
req.environ['swift.cache'] = memcache
|
||||
self.assertNotIn('swift.access_logging', req.environ)
|
||||
resp = req.get_response(ath)
|
||||
self.assertEqual(req.environ['swift.access_logging'],
|
||||
{'user_id': 't\u00e9st:t\u00e9ster'})
|
||||
self.assertEqual(204, resp.status_int)
|
||||
|
||||
# ...but it also works if you send the account raw
|
||||
|
||||
Reference in New Issue
Block a user