From 136721428fa506668592c2601b912ec6115ad52c Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Thu, 15 Dec 2016 21:16:44 +0000 Subject: [PATCH] Fix far-future date handling Previously, if a user-provided timestamp was after the largest-possible Swift timestamp, we would raise AccessDenied. However, AWS continues to complain about time skew. Note that we may regret this come 2286, but by then I'll be dead. Change-Id: I88952a28a7e7c42540c61514f82582815fabf611 --- swift3/request.py | 13 +++++- swift3/response.py | 2 +- .../conf/ceph-known-failures-keystone.yaml | 1 - .../conf/ceph-known-failures-tempauth.yaml | 1 - swift3/test/unit/test_request.py | 45 ++++++++++++++++++- 5 files changed, 56 insertions(+), 6 deletions(-) diff --git a/swift3/request.py b/swift3/request.py index 758d8d5d..25a567da 100644 --- a/swift3/request.py +++ b/swift3/request.py @@ -138,10 +138,15 @@ class SigV4Mixin(object): raise AccessDenied('AWS authentication requires a valid Date ' 'or x-amz-date header') + if timestamp < 0: + raise AccessDenied('AWS authentication requires a valid Date ' + 'or x-amz-date header') + try: self._timestamp = S3Timestamp(timestamp) except ValueError: - raise AccessDenied() + # Must be far-future; blame clock skew + raise RequestTimeTooSkewed() return self._timestamp @@ -422,10 +427,14 @@ class Request(swob.Request): raise AccessDenied('AWS authentication requires a valid Date ' 'or x-amz-date header') + if timestamp < 0: + raise AccessDenied('AWS authentication requires a valid Date ' + 'or x-amz-date header') try: self._timestamp = S3Timestamp(timestamp) except ValueError: - raise AccessDenied() + # Must be far-future; blame clock skew + raise RequestTimeTooSkewed() return self._timestamp diff --git a/swift3/response.py b/swift3/response.py index 6f9ef3cd..203292f4 100644 --- a/swift3/response.py +++ b/swift3/response.py @@ -604,7 +604,7 @@ class RequestTimeout(ErrorResponse): class RequestTimeTooSkewed(ErrorResponse): _status = '403 Forbidden' - _msg = 'The difference between the request time and the server\'s time ' \ + _msg = 'The difference between the request time and the current time ' \ 'is too large.' diff --git a/swift3/test/functional/conf/ceph-known-failures-keystone.yaml b/swift3/test/functional/conf/ceph-known-failures-keystone.yaml index 3f0627a0..cfeb3e66 100644 --- a/swift3/test/functional/conf/ceph-known-failures-keystone.yaml +++ b/swift3/test/functional/conf/ceph-known-failures-keystone.yaml @@ -5,7 +5,6 @@ ceph_s3: s3tests.functional.test_headers.test_bucket_create_bad_authorization_none: {status: KNOWN} s3tests.functional.test_headers.test_object_create_bad_authorization_invalid_aws2: {status: KNOWN} s3tests.functional.test_headers.test_object_create_bad_authorization_none: {status: KNOWN} - s3tests.functional.test_headers.test_object_create_bad_date_after_end_aws2: {status: KNOWN} s3tests.functional.test_s3.test_100_continue: {status: KNOWN} s3tests.functional.test_s3.test_abort_multipart_upload: {status: KNOWN} s3tests.functional.test_s3.test_abort_multipart_upload_not_found: {status: KNOWN} diff --git a/swift3/test/functional/conf/ceph-known-failures-tempauth.yaml b/swift3/test/functional/conf/ceph-known-failures-tempauth.yaml index e33118c7..ae8a6909 100644 --- a/swift3/test/functional/conf/ceph-known-failures-tempauth.yaml +++ b/swift3/test/functional/conf/ceph-known-failures-tempauth.yaml @@ -5,7 +5,6 @@ ceph_s3: s3tests.functional.test_headers.test_bucket_create_bad_authorization_none: {status: KNOWN} s3tests.functional.test_headers.test_object_create_bad_authorization_invalid_aws2: {status: KNOWN} s3tests.functional.test_headers.test_object_create_bad_authorization_none: {status: KNOWN} - s3tests.functional.test_headers.test_object_create_bad_date_after_end_aws2: {status: KNOWN} s3tests.functional.test_s3.test_100_continue: {status: KNOWN} s3tests.functional.test_s3.test_atomic_conditional_write_1mb: {status: KNOWN} s3tests.functional.test_s3.test_atomic_dual_conditional_write_1mb: {status: KNOWN} diff --git a/swift3/test/unit/test_request.py b/swift3/test/unit/test_request.py index acb5c276..893a1bb6 100644 --- a/swift3/test/unit/test_request.py +++ b/swift3/test/unit/test_request.py @@ -27,7 +27,7 @@ from swift3.cfg import CONF from swift3.request import Request as S3_Request from swift3.request import S3AclRequest, SigV4Request, SIGV4_X_AMZ_DATE_FORMAT from swift3.response import InvalidArgument, NoSuchBucket, InternalError, \ - AccessDenied, SignatureDoesNotMatch + AccessDenied, SignatureDoesNotMatch, RequestTimeTooSkewed Fake_ACL_MAP = { @@ -439,6 +439,24 @@ class TestRequest(Swift3TestCase): self._test_request_timestamp_sigv4(date_header) self.assertEqual('403 Forbidden', cm.exception.message) + self.assertIn(access_denied_message, cm.exception.body) + + # far-past Date header + date_header = {'Date': 'Tue, 07 Jul 999 21:53:04 GMT'} + with self.assertRaises(AccessDenied) as cm: + self._test_request_timestamp_sigv4(date_header) + + self.assertEqual('403 Forbidden', cm.exception.message) + self.assertIn(access_denied_message, cm.exception.body) + + # far-future Date header + date_header = {'Date': 'Tue, 07 Jul 9999 21:53:04 GMT'} + with self.assertRaises(RequestTimeTooSkewed) as cm: + self._test_request_timestamp_sigv4(date_header) + + self.assertEqual('403 Forbidden', cm.exception.message) + self.assertIn('The difference between the request time and the ' + 'current time is too large.', cm.exception.body) def _test_request_timestamp_sigv2(self, date_header): # signature v4 here @@ -486,6 +504,31 @@ class TestRequest(Swift3TestCase): self.assertEqual('403 Forbidden', cm.exception.message) self.assertIn(access_denied_message, cm.exception.body) + # Negative timestamp + date_header = {'X-Amz-Date': '00160523T054055Z'} + with self.assertRaises(AccessDenied) as cm: + self._test_request_timestamp_sigv2(date_header) + + self.assertEqual('403 Forbidden', cm.exception.message) + self.assertIn(access_denied_message, cm.exception.body) + + # far-past Date header + date_header = {'Date': 'Tue, 07 Jul 999 21:53:04 GMT'} + with self.assertRaises(AccessDenied) as cm: + self._test_request_timestamp_sigv2(date_header) + + self.assertEqual('403 Forbidden', cm.exception.message) + self.assertIn(access_denied_message, cm.exception.body) + + # far-future Date header + date_header = {'Date': 'Tue, 07 Jul 9999 21:53:04 GMT'} + with self.assertRaises(RequestTimeTooSkewed) as cm: + self._test_request_timestamp_sigv2(date_header) + + self.assertEqual('403 Forbidden', cm.exception.message) + self.assertIn('The difference between the request time and the ' + 'current time is too large.', cm.exception.body) + def test_headers_to_sign_sigv4(self): environ = { 'REQUEST_METHOD': 'GET'}