diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-01-22 15:19:33 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-01-22 15:19:33 +0000 |
commit | db4072b30be7d1fbb105f2db4b7f7fcf3ed58064 (patch) | |
tree | 3ddec2ad92491a241f604e9d5555c18dea208c0b | |
parent | 16bda43d3a95987fbd70946ef399048db23e16ee (diff) | |
parent | 949a2cdc3a4e15b3df56b79473d97c16fda9f422 (diff) | |
download | keystone-db4072b30be7d1fbb105f2db4b7f7fcf3ed58064.tar.gz |
Merge "Store ec2 credentials blob as json"
-rw-r--r-- | keystone/contrib/ec2/controllers.py | 14 | ||||
-rw-r--r-- | keystone/tests/test_v3_credential.py | 91 |
2 files changed, 101 insertions, 4 deletions
diff --git a/keystone/contrib/ec2/controllers.py b/keystone/contrib/ec2/controllers.py index 966ac68fe..44b1549ca 100644 --- a/keystone/contrib/ec2/controllers.py +++ b/keystone/contrib/ec2/controllers.py @@ -44,6 +44,8 @@ from keystone.common import utils from keystone import exception from keystone import token +from keystone.openstack.common import jsonutils + @dependency.requires('assignment_api', 'catalog_api', 'credential_api', 'identity_api', 'token_api', 'token_provider_api') @@ -158,7 +160,7 @@ class Ec2Controller(controller.V2Controller): credential_id = utils.hash_access_key(blob['access']) cred_ref = {'user_id': user_id, 'project_id': tenant_id, - 'blob': blob, + 'blob': jsonutils.dumps(blob), 'id': credential_id, 'type': 'ec2'} self.credential_api.create_credential(credential_id, cred_ref) @@ -215,8 +217,14 @@ class Ec2Controller(controller.V2Controller): return self.credential_api.delete_credential(ec2_credential_id) def _convert_v3_to_ec2_credential(self, credential): - - blob = credential['blob'] + # Prior to bug #1259584 fix, blob was stored unserialized + # but it should be stored as a json string for compatibility + # with the v3 credentials API. Fall back to the old behavior + # for backwards compatibility with existing DB contents + try: + blob = jsonutils.loads(credential['blob']) + except TypeError: + blob = credential['blob'] return {'user_id': credential.get('user_id'), 'tenant_id': credential.get('project_id'), 'access': blob.get('access'), diff --git a/keystone/tests/test_v3_credential.py b/keystone/tests/test_v3_credential.py index c2b032769..a9735075b 100644 --- a/keystone/tests/test_v3_credential.py +++ b/keystone/tests/test_v3_credential.py @@ -18,11 +18,36 @@ import hashlib import json import uuid +from keystoneclient.contrib.ec2 import utils as ec2_utils + from keystone import exception from keystone.tests import test_v3 -class CredentialTestCase(test_v3.RestfulTestCase): +class CredentialBaseTestCase(test_v3.RestfulTestCase): + def _create_dict_blob_credential(self): + blob = {"access": uuid.uuid4().hex, + "secret": uuid.uuid4().hex} + credential_id = hashlib.sha256(blob['access']).hexdigest() + credential = self.new_credential_ref( + user_id=self.user['id'], + project_id=self.project_id) + credential['id'] = credential_id + + # Store the blob as a dict *not* JSON ref bug #1259584 + # This means we can test the dict->json workaround, added + # as part of the bugfix for backwards compatibility works. + credential['blob'] = blob + credential['type'] = 'ec2' + # Create direct via the DB API to avoid validation failure + self.credential_api.create_credential( + credential_id, + credential) + expected_blob = json.dumps(blob) + return expected_blob, credential_id + + +class CredentialTestCase(CredentialBaseTestCase): """Test credential CRUD.""" def setUp(self): @@ -212,3 +237,67 @@ class TestCredentialTrustScoped(test_v3.RestfulTestCase): body={'credential': ref}, token=token_id, expected_status=409) + + +class TestCredentialEc2(CredentialBaseTestCase): + """Test v3 credential compatibility with ec2tokens.""" + def setUp(self): + super(TestCredentialEc2, self).setUp() + + def _validate_signature(self, access, secret): + """Test signature validation with the access/secret provided.""" + signer = ec2_utils.Ec2Signer(secret) + params = {'SignatureMethod': 'HmacSHA256', + 'SignatureVersion': '2', + 'AWSAccessKeyId': access} + request = {'host': 'foo', + 'verb': 'GET', + 'path': '/bar', + 'params': params} + signature = signer.generate(request) + + # Now make a request to validate the signed dummy request via the + # ec2tokens API. This proves the v3 ec2 credentials actually work. + sig_ref = {'access': access, + 'signature': signature, + 'host': 'foo', + 'verb': 'GET', + 'path': '/bar', + 'params': params} + r = self.post( + '/ec2tokens', + body={'ec2Credentials': sig_ref}, + expected_status=200) + # FIXME(shardy): ec2tokens is available via both v3 and v2 + # paths, but it returns a v2 token in both cases, so we can + # only do a sanity assertion here for now. + self.assertIsNotNone(r.result['access']['token']['id']) + + def test_ec2_credential_signature_validate(self): + """Test signature validation with a v3 ec2 credential.""" + ref = self.new_credential_ref( + user_id=self.user['id'], + project_id=self.project_id) + blob = {"access": uuid.uuid4().hex, + "secret": uuid.uuid4().hex} + ref['blob'] = json.dumps(blob) + ref['type'] = 'ec2' + r = self.post( + '/credentials', + body={'credential': ref}) + self.assertValidCredentialResponse(r, ref) + # Assert credential id is same as hash of access key id + self.assertEqual(r.result['credential']['id'], + hashlib.sha256(blob['access']).hexdigest()) + + cred_blob = json.loads(r.result['credential']['blob']) + self.assertEqual(blob, cred_blob) + self._validate_signature(access=cred_blob['access'], + secret=cred_blob['secret']) + + def test_ec2_credential_signature_validate_legacy(self): + """Test signature validation with a legacy v3 ec2 credential.""" + cred_json, credential_id = self._create_dict_blob_credential() + cred_blob = json.loads(cred_json) + self._validate_signature(access=cred_blob['access'], + secret=cred_blob['secret']) |