From aa2dea35c6e1cfc913e85834b9b98eda4155bd06 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 2 Jan 2013 13:10:01 -0800 Subject: [PATCH] Allow larger encrypted password posts to metadata System Metadata only supports values up to 255 characters, but passwords encrypted with an rsa key are generally much longer than that, so we support longer passwords by chunking into four fields. Change-Id: Iceae6cbc7609ec3bdf1b3814aec5b73f19613349 --- nova/api/metadata/base.py | 7 +------ nova/api/metadata/password.py | 34 +++++++++++++++++++++++++++++----- nova/tests/test_metadata.py | 3 ++- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/nova/api/metadata/base.py b/nova/api/metadata/base.py index 2377da7b75fc..34d412268a9a 100644 --- a/nova/api/metadata/base.py +++ b/nova/api/metadata/base.py @@ -136,12 +136,7 @@ class InstanceMetadata(): for item in instance.get('metadata', []): self.launch_metadata[item['key']] = item['value'] - self.password = '' - # get password if set - for item in instance.get('system_metadata', []): - if item['key'] == 'password': - self.password = item['value'] or '' - break + self.password = password.extract_password(instance) self.uuid = instance.get('uuid') diff --git a/nova/api/metadata/password.py b/nova/api/metadata/password.py index 3cda67eee39a..b2bb83b15014 100644 --- a/nova/api/metadata/password.py +++ b/nova/api/metadata/password.py @@ -19,7 +19,34 @@ from nova import context from nova import db -MAX_SIZE = 256 +CHUNKS = 4 +CHUNK_LENGTH = 255 +MAX_SIZE = CHUNKS * CHUNK_LENGTH + + +def extract_password(instance): + result = '' + for datum in sorted(instance.get('system_metadata', []), + key=lambda x: x['key']): + if datum['key'].startswith('password_'): + result += datum['value'] + return result or None + + +def set_password(context, instance_uuid, password): + """Stores password as system_metadata items. + + Password is stored with the keys 'password_0' -> 'password_3'. + """ + password = password or '' + meta = {} + for i in xrange(CHUNKS): + meta['password_%d' % i] = password[:CHUNK_LENGTH] + password = password[CHUNK_LENGTH:] + db.instance_system_metadata_update(context, + instance_uuid, + meta, + False) def handle_password(req, meta_data): @@ -36,9 +63,6 @@ def handle_password(req, meta_data): if (req.content_length > MAX_SIZE or len(req.body) > MAX_SIZE): msg = _("Request is too large.") raise exc.HTTPBadRequest(explanation=msg) - db.instance_system_metadata_update(ctxt, - meta_data.uuid, - {'password': req.body}, - False) + set_password(ctxt, meta_data.uuid, req.body) else: raise exc.HTTPBadRequest() diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py index 1f2ea4bc553d..25c26ca9cd90 100644 --- a/nova/tests/test_metadata.py +++ b/nova/tests/test_metadata.py @@ -550,4 +550,5 @@ class MetadataPasswordTestCase(test.TestCase): def test_too_large(self): self.mdinst.password = '' self.assertRaises(webob.exc.HTTPBadRequest, - self._try_set_password, 'a' * 257) + self._try_set_password, + 'a' * (password.MAX_SIZE + 1))