diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-10-29 20:26:56 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-10-29 20:26:56 +0000 |
| commit | cb72ff1fa700f5a8be172df5a14dd479bf75fa36 (patch) | |
| tree | 104a9db3fe6a700b968b29fa195a4d74186e4777 | |
| parent | 6143e90d77c4f3301000337a43a2c9782d785301 (diff) | |
| parent | 1056677bb6e5bda331270100b577f085cd0b5067 (diff) | |
| download | nova-cb72ff1fa700f5a8be172df5a14dd479bf75fa36.tar.gz nova-cb72ff1fa700f5a8be172df5a14dd479bf75fa36.tar.xz nova-cb72ff1fa700f5a8be172df5a14dd479bf75fa36.zip | |
Merge "Validates Timestamp or Expiry time in EC2 requests"
| -rw-r--r-- | nova/api/ec2/__init__.py | 12 | ||||
| -rw-r--r-- | nova/api/ec2/ec2utils.py | 34 | ||||
| -rw-r--r-- | nova/tests/api/ec2/test_ec2_validate.py | 81 |
3 files changed, 127 insertions, 0 deletions
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 2ae685cec..d1145420e 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -66,6 +66,9 @@ ec2_opts = [ default=True, help='Validate security group names' ' according to EC2 specification'), + cfg.IntOpt('ec2_timestamp_expiry', + default=300, + help='Time in seconds before ec2 timestamp expires'), ] FLAGS = flags.FLAGS @@ -311,6 +314,13 @@ class Requestify(wsgi.Middleware): 'SignatureVersion', 'Version', 'Timestamp'] args = dict(req.params) try: + expired = ec2utils.is_ec2_timestamp_expired(req.params, + expires=FLAGS.ec2_timestamp_expiry) + if expired: + msg = _("Timestamp failed validation.") + LOG.exception(msg) + raise webob.exc.HTTPForbidden(detail=msg) + # Raise KeyError if omitted action = req.params['Action'] # Fix bug lp:720157 for older (version 1) clients @@ -324,6 +334,8 @@ class Requestify(wsgi.Middleware): args.pop(non_arg) except KeyError, e: raise webob.exc.HTTPBadRequest() + except exception.InvalidRequest as err: + raise webob.exc.HTTPBadRequest(explanation=unicode(err)) LOG.debug(_('action: %s'), action) for key, value in args.items(): diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py index fdff3d9f4..4d0a926df 100644 --- a/nova/api/ec2/ec2utils.py +++ b/nova/api/ec2/ec2utils.py @@ -24,6 +24,7 @@ from nova import exception from nova import flags from nova.network import model as network_model from nova.openstack.common import log as logging +from nova.openstack.common import timeutils from nova import utils @@ -176,6 +177,39 @@ def ec2_vol_id_to_uuid(ec2_id): return get_volume_uuid_from_int_id(ctxt, int_id) +def is_ec2_timestamp_expired(request, expires=None): + """Checks the timestamp or expiry time included in a EC2 request + and returns true if the request is expired + """ + query_time = None + timestamp = request.get('Timestamp') + expiry_time = request.get('Expires') + try: + if timestamp and expiry_time: + msg = _("Request must include either Timestamp or Expires," + " but cannot contain both") + LOG.error(msg) + raise exception.InvalidRequest(msg) + elif expiry_time: + query_time = timeutils.parse_strtime(expiry_time, + "%Y-%m-%dT%H:%M:%SZ") + return timeutils.is_older_than(query_time, -1) + elif timestamp: + query_time = timeutils.parse_strtime(timestamp, + "%Y-%m-%dT%H:%M:%SZ") + + # Check if the difference between the timestamp in the request + # and the time on our servers is larger than 5 minutes, the + # request is too old (or too new). + if query_time and expires: + return timeutils.is_older_than(query_time, expires) or \ + timeutils.is_newer_than(query_time, expires) + return False + except ValueError: + LOG.audit(_("Timestamp is invalid.")) + return True + + def get_int_id_from_instance_uuid(context, instance_uuid): if instance_uuid is None: return diff --git a/nova/tests/api/ec2/test_ec2_validate.py b/nova/tests/api/ec2/test_ec2_validate.py index f46262c35..c9c11d547 100644 --- a/nova/tests/api/ec2/test_ec2_validate.py +++ b/nova/tests/api/ec2/test_ec2_validate.py @@ -16,7 +16,10 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime + from nova.api.ec2 import cloud +from nova.api.ec2 import ec2utils from nova.compute import utils as compute_utils from nova import context from nova import db @@ -24,6 +27,7 @@ from nova import exception from nova import flags from nova.openstack.common import log as logging from nova.openstack.common import rpc +from nova.openstack.common import timeutils from nova import test from nova.tests import fake_network from nova.tests.image import fake @@ -166,3 +170,80 @@ class EC2ValidateTestCase(test.TestCase): self.cloud.detach_volume, context=self.context, volume_id=ec2_id) + + +class EC2TimestampValidationTestCase(test.TestCase): + """Test case for EC2 request timestamp validation""" + + def test_validate_ec2_timestamp_valid(self): + params = {'Timestamp': '2011-04-22T11:29:49Z'} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertFalse(expired) + + def test_validate_ec2_timestamp_old_format(self): + params = {'Timestamp': '2011-04-22T11:29:49'} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertTrue(expired) + + def test_validate_ec2_timestamp_not_set(self): + params = {} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertFalse(expired) + + def test_validate_ec2_timestamp_invalid_format(self): + params = {'Timestamp': '2011-04-22T11:29:49.000P'} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertTrue(expired) + + def test_validate_ec2_timestamp_advanced_time(self): + + #EC2 request with Timestamp in advanced time + timestamp = timeutils.utcnow() + datetime.timedelta(seconds=250) + params = {'Timestamp': timeutils.strtime(timestamp, + "%Y-%m-%dT%H:%M:%SZ")} + expired = ec2utils.is_ec2_timestamp_expired(params, expires=300) + self.assertFalse(expired) + + def test_validate_ec2_timestamp_advanced_time_expired(self): + timestamp = timeutils.utcnow() + datetime.timedelta(seconds=350) + params = {'Timestamp': timeutils.strtime(timestamp, + "%Y-%m-%dT%H:%M:%SZ")} + expired = ec2utils.is_ec2_timestamp_expired(params, expires=300) + self.assertTrue(expired) + + def test_validate_ec2_req_timestamp_not_expired(self): + params = {'Timestamp': timeutils.isotime()} + expired = ec2utils.is_ec2_timestamp_expired(params, expires=15) + self.assertFalse(expired) + + def test_validate_ec2_req_timestamp_expired(self): + params = {'Timestamp': '2011-04-22T12:00:00Z'} + compare = ec2utils.is_ec2_timestamp_expired(params, expires=300) + self.assertTrue(compare) + + def test_validate_ec2_req_expired(self): + params = {'Expires': timeutils.isotime()} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertTrue(expired) + + def test_validate_ec2_req_not_expired(self): + expire = timeutils.utcnow() + datetime.timedelta(seconds=350) + params = {'Expires': timeutils.strtime(expire, "%Y-%m-%dT%H:%M:%SZ")} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertFalse(expired) + + def test_validate_Expires_timestamp_invalid_format(self): + + #EC2 request with invalid Expires + params = {'Expires': '2011-04-22T11:29:49'} + expired = ec2utils.is_ec2_timestamp_expired(params) + self.assertTrue(expired) + + def test_validate_ec2_req_timestamp_Expires(self): + + #EC2 request with both Timestamp and Expires + params = {'Timestamp': '2011-04-22T11:29:49Z', + 'Expires': timeutils.isotime()} + self.assertRaises(exception.InvalidRequest, + ec2utils.is_ec2_timestamp_expired, + params) |
