summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-10-29 20:26:56 +0000
committerGerrit Code Review <review@openstack.org>2012-10-29 20:26:56 +0000
commitcb72ff1fa700f5a8be172df5a14dd479bf75fa36 (patch)
tree104a9db3fe6a700b968b29fa195a4d74186e4777
parent6143e90d77c4f3301000337a43a2c9782d785301 (diff)
parent1056677bb6e5bda331270100b577f085cd0b5067 (diff)
downloadnova-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__.py12
-rw-r--r--nova/api/ec2/ec2utils.py34
-rw-r--r--nova/tests/api/ec2/test_ec2_validate.py81
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)