From d8fb4f1794158e61874525828383795772352075 Mon Sep 17 00:00:00 2001 From: Kaitlin Farr Date: Tue, 29 Aug 2017 10:25:37 -0400 Subject: [PATCH] Add ID to managed objects The managed objects did not have an ID associated with them. This is most helpful for the list command, where once you have more than one object, it's hard to track unique identifiers for the objects. Change-Id: Ibc48762e7c2c71659fb96826c53301bc6f55ddf7 --- castellan/common/objects/managed_object.py | 14 +++++++++++++- castellan/common/objects/opaque_data.py | 4 ++-- castellan/common/objects/passphrase.py | 4 ++-- castellan/common/objects/private_key.py | 4 ++-- castellan/common/objects/public_key.py | 4 ++-- castellan/common/objects/symmetric_key.py | 4 ++-- castellan/common/objects/x_509.py | 4 ++-- castellan/key_manager/barbican_key_manager.py | 11 +++++++++-- .../functional/key_manager/test_key_manager.py | 15 +++++++++++---- .../tests/unit/key_manager/mock_key_manager.py | 1 + .../key_manager/test_barbican_key_manager.py | 10 ++++++++++ .../unit/key_manager/test_mock_key_manager.py | 17 +++++++++++++++++ 12 files changed, 73 insertions(+), 19 deletions(-) diff --git a/castellan/common/objects/managed_object.py b/castellan/common/objects/managed_object.py index 58d05894..de3c2e71 100644 --- a/castellan/common/objects/managed_object.py +++ b/castellan/common/objects/managed_object.py @@ -28,11 +28,12 @@ import six class ManagedObject(object): """Base class to represent all managed objects.""" - def __init__(self, name=None, created=None): + def __init__(self, name=None, created=None, id=None): """Managed Object :param name: the name of the managed object. :param created: the time a managed object was created. + :param id: the ID of the object, generated after storing the object. """ self._name = name @@ -43,6 +44,17 @@ class ManagedObject(object): raise ValueError('created must be of long type, actual type %s' % type(created)) + self._id = id + + @property + def id(self): + """Returns the ID of the managed object. + + Returns the ID of the managed object or None if this object does not + have one. If the ID is None, the object has not been persisted yet. + """ + return self._id + @property def name(self): """Returns the name. diff --git a/castellan/common/objects/opaque_data.py b/castellan/common/objects/opaque_data.py index 81b8e45a..9512ba25 100644 --- a/castellan/common/objects/opaque_data.py +++ b/castellan/common/objects/opaque_data.py @@ -25,13 +25,13 @@ from castellan.common.objects import managed_object class OpaqueData(managed_object.ManagedObject): """This class represents opaque data.""" - def __init__(self, data, name=None, created=None): + def __init__(self, data, name=None, created=None, id=None): """Create a new OpaqueData object. Expected type for data is a bytestring. """ self._data = data - super(OpaqueData, self).__init__(name=name, created=created) + super(OpaqueData, self).__init__(name=name, created=created, id=id) @property def format(self): diff --git a/castellan/common/objects/passphrase.py b/castellan/common/objects/passphrase.py index 346d8f6f..e0441b52 100644 --- a/castellan/common/objects/passphrase.py +++ b/castellan/common/objects/passphrase.py @@ -25,13 +25,13 @@ from castellan.common.objects import managed_object class Passphrase(managed_object.ManagedObject): """This class represents a passphrase.""" - def __init__(self, passphrase, name=None, created=None): + def __init__(self, passphrase, name=None, created=None, id=None): """Create a new Passphrase object. The expected type for the passphrase is a bytestring. """ self._passphrase = passphrase - super(Passphrase, self).__init__(name=name, created=created) + super(Passphrase, self).__init__(name=name, created=created, id=id) @property def format(self): diff --git a/castellan/common/objects/private_key.py b/castellan/common/objects/private_key.py index 45d936aa..6472ef87 100644 --- a/castellan/common/objects/private_key.py +++ b/castellan/common/objects/private_key.py @@ -26,7 +26,7 @@ class PrivateKey(key.Key): """This class represents private keys.""" def __init__(self, algorithm, bit_length, key, - name=None, created=None): + name=None, created=None, id=None): """Create a new PrivateKey object. The arguments specify the algorithm and bit length for the asymmetric @@ -35,7 +35,7 @@ class PrivateKey(key.Key): self._alg = algorithm self._bit_length = bit_length self._key = key - super(PrivateKey, self).__init__(name=name, created=created) + super(PrivateKey, self).__init__(name=name, created=created, id=id) @property def algorithm(self): diff --git a/castellan/common/objects/public_key.py b/castellan/common/objects/public_key.py index 6d11eb30..efcc6b57 100644 --- a/castellan/common/objects/public_key.py +++ b/castellan/common/objects/public_key.py @@ -26,7 +26,7 @@ class PublicKey(key.Key): """This class represents public keys.""" def __init__(self, algorithm, bit_length, key, - name=None, created=None): + name=None, created=None, id=None): """Create a new PublicKey object. The arguments specify the algorithm and bit length for the asymmetric @@ -36,7 +36,7 @@ class PublicKey(key.Key): self._alg = algorithm self._bit_length = bit_length self._key = key - super(PublicKey, self).__init__(name=name, created=created) + super(PublicKey, self).__init__(name=name, created=created, id=id) @property def algorithm(self): diff --git a/castellan/common/objects/symmetric_key.py b/castellan/common/objects/symmetric_key.py index 499c1590..f9cefeb3 100644 --- a/castellan/common/objects/symmetric_key.py +++ b/castellan/common/objects/symmetric_key.py @@ -26,7 +26,7 @@ class SymmetricKey(key.Key): """This class represents symmetric keys.""" def __init__(self, algorithm, bit_length, key, - name=None, created=None): + name=None, created=None, id=None): """Create a new SymmetricKey object. The arguments specify the algorithm and bit length for the symmetric @@ -35,7 +35,7 @@ class SymmetricKey(key.Key): self._alg = algorithm self._bit_length = bit_length self._key = key - super(SymmetricKey, self).__init__(name=name, created=created) + super(SymmetricKey, self).__init__(name=name, created=created, id=id) @property def algorithm(self): diff --git a/castellan/common/objects/x_509.py b/castellan/common/objects/x_509.py index 8eaa1c95..aba1a88a 100644 --- a/castellan/common/objects/x_509.py +++ b/castellan/common/objects/x_509.py @@ -25,13 +25,13 @@ from castellan.common.objects import certificate class X509(certificate.Certificate): """This class represents X.509 certificates.""" - def __init__(self, data, name=None, created=None): + def __init__(self, data, name=None, created=None, id=None): """Create a new X509 object. The data should be in a bytestring. """ self._data = data - super(X509, self).__init__(name=name, created=created) + super(X509, self).__init__(name=name, created=created, id=id) @property def format(self): diff --git a/castellan/key_manager/barbican_key_manager.py b/castellan/key_manager/barbican_key_manager.py index a39116b2..8b488b5d 100644 --- a/castellan/key_manager/barbican_key_manager.py +++ b/castellan/key_manager/barbican_key_manager.py @@ -480,6 +480,11 @@ class BarbicanKeyManager(key_manager.KeyManager): else: secret_data = self._get_secret_data(secret) + if secret.secret_ref: + object_id = self._retrieve_secret_uuid(secret.secret_ref) + else: + object_id = None + # convert created ISO8601 in Barbican to POSIX if secret.created: time_stamp = timeutils.parse_isotime( @@ -491,11 +496,13 @@ class BarbicanKeyManager(key_manager.KeyManager): secret.bit_length, secret_data, secret.name, - created) + created, + object_id) else: return secret_type(secret_data, secret.name, - created) + created, + object_id) def _get_secret(self, context, object_id): """Returns the metadata of the secret. diff --git a/castellan/tests/functional/key_manager/test_key_manager.py b/castellan/tests/functional/key_manager/test_key_manager.py index f62dee3a..1f8eaf6b 100644 --- a/castellan/tests/functional/key_manager/test_key_manager.py +++ b/castellan/tests/functional/key_manager/test_key_manager.py @@ -137,6 +137,8 @@ class KeyManagerTestCase(object): self.assertEqual(managed_object.get_encoded(), retrieved_object.get_encoded()) self.assertFalse(managed_object.is_metadata_only()) + self.assertFalse(retrieved_object.is_metadata_only()) + self.assertIsNotNone(retrieved_object.id) @utils.parameterized_dataset({ 'symmetric_key': [_get_test_symmetric_key()], @@ -155,6 +157,7 @@ class KeyManagerTestCase(object): metadata_only=True) self.assertFalse(managed_object.is_metadata_only()) self.assertTrue(retrieved_object.is_metadata_only()) + self.assertIsNotNone(retrieved_object.id) @utils.parameterized_dataset({ 'symmetric_key': [_get_test_symmetric_key()], @@ -171,6 +174,7 @@ class KeyManagerTestCase(object): retrieved_object = self.key_mgr.get(self.ctxt, uuid) self.assertEqual(managed_object.get_encoded(), retrieved_object.get_encoded()) + self.assertIsNotNone(retrieved_object.id) @utils.parameterized_dataset({ 'symmetric_key': [_get_test_symmetric_key()], @@ -189,8 +193,9 @@ class KeyManagerTestCase(object): # check if the object we created is in the list retrieved_objects = self.key_mgr.list(self.ctxt) self.assertTrue(managed_object in retrieved_objects) - for obj in retrieved_objects: - self.assertFalse(obj.is_metadata_only()) + for retrieved_object in retrieved_objects: + self.assertFalse(retrieved_object.is_metadata_only()) + self.assertIsNotNone(retrieved_object.id) @utils.parameterized_dataset({ 'symmetric_key': [_get_test_symmetric_key()], @@ -211,8 +216,9 @@ class KeyManagerTestCase(object): # check if the object we created is in the list retrieved_objects = self.key_mgr.list(self.ctxt, metadata_only=True) self.assertTrue(expected_obj in retrieved_objects) - for obj in retrieved_objects: - self.assertTrue(obj.is_metadata_only()) + for retrieved_object in retrieved_objects: + self.assertTrue(retrieved_object.is_metadata_only()) + self.assertIsNotNone(retrieved_object.id) @utils.parameterized_dataset({ 'query_by_object_type': { @@ -233,4 +239,5 @@ class KeyManagerTestCase(object): retrieved_objects = self.key_mgr.list(self.ctxt, **query_dict) for retrieved_object in retrieved_objects: self.assertEqual(type(object_1), type(retrieved_object)) + self.assertIsNotNone(retrieved_object.id) self.assertTrue(object_1 in retrieved_objects) diff --git a/castellan/tests/unit/key_manager/mock_key_manager.py b/castellan/tests/unit/key_manager/mock_key_manager.py index b9812925..5fee24b8 100644 --- a/castellan/tests/unit/key_manager/mock_key_manager.py +++ b/castellan/tests/unit/key_manager/mock_key_manager.py @@ -163,6 +163,7 @@ class MockKeyManager(key_manager.KeyManager): raise exception.Forbidden() key_id = self._generate_key_id() + managed_object._id = key_id self.keys[key_id] = managed_object return key_id diff --git a/castellan/tests/unit/key_manager/test_barbican_key_manager.py b/castellan/tests/unit/key_manager/test_barbican_key_manager.py index 5d5668cf..f3fdb10a 100644 --- a/castellan/tests/unit/key_manager/test_barbican_key_manager.py +++ b/castellan/tests/unit/key_manager/test_barbican_key_manager.py @@ -189,6 +189,10 @@ class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase): original_secret_metadata.bit_length = mock.sentinel.bit original_secret_metadata.secret_type = 'symmetric' + key_id = "43ed09c3-e551-4c24-b612-e619abe9b534" + key_ref = ("http://localhost:9311/v1/secrets/" + key_id) + original_secret_metadata.secret_ref = key_ref + created = timeutils.parse_isotime('2015-10-20 18:51:17+00:00') original_secret_metadata.created = created created_formatted = timeutils.parse_isotime(str(created)) @@ -204,6 +208,7 @@ class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase): key = self.key_mgr.get(self.ctxt, self.key_id) self.get.assert_called_once_with(self.secret_ref) + self.assertEqual(key_id, key.id) self.assertEqual(key_name, key.name) self.assertEqual(original_secret_data, key.get_encoded()) self.assertEqual(created_posix, key.created) @@ -360,6 +365,10 @@ class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase): original_secret_metadata.bit_length = mock.sentinel.bit original_secret_metadata.secret_type = 'symmetric' + key_id = "43ed09c3-e551-4c24-b612-e619abe9b534" + key_ref = ("http://localhost:9311/v1/secrets/" + key_id) + original_secret_metadata.secret_ref = key_ref + created = timeutils.parse_isotime('2015-10-20 18:51:17+00:00') original_secret_metadata.created = created created_formatted = timeutils.parse_isotime(str(created)) @@ -380,6 +389,7 @@ class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase): key = key_list[0] self.list.assert_called_once() + self.assertEqual(key_id, key.id) self.assertEqual(key_name, key.name) self.assertEqual(original_secret_data, key.get_encoded()) self.assertEqual(created_posix, key.created) diff --git a/castellan/tests/unit/key_manager/test_mock_key_manager.py b/castellan/tests/unit/key_manager/test_mock_key_manager.py index dd2d6e74..aef41559 100644 --- a/castellan/tests/unit/key_manager/test_mock_key_manager.py +++ b/castellan/tests/unit/key_manager/test_mock_key_manager.py @@ -70,18 +70,21 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): key_id = self.key_mgr.create_key(self.context, length=length) key = self.key_mgr.get(self.context, key_id) self.assertEqual(length / 8, len(key.get_encoded())) + self.assertIsNotNone(key.id) def test_create_key_with_name(self): name = 'my key' key_id = self.key_mgr.create_key(self.context, name=name) key = self.key_mgr.get(self.context, key_id) self.assertEqual(name, key.name) + self.assertIsNotNone(key.id) def test_create_key_with_algorithm(self): algorithm = 'DES' key_id = self.key_mgr.create_key(self.context, algorithm=algorithm) key = self.key_mgr.get(self.context, key_id) self.assertEqual(algorithm, key.algorithm) + self.assertIsNotNone(key.id) def test_create_key_null_context(self): self.assertRaises(exception.Forbidden, @@ -94,7 +97,9 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): self.context, 'RSA', length, name=name) private_key = self.key_mgr.get(self.context, private_key_uuid) + self.assertIsNotNone(private_key.id) public_key = self.key_mgr.get(self.context, public_key_uuid) + self.assertIsNotNone(public_key.id) crypto_private_key = get_cryptography_private_key(private_key) crypto_public_key = get_cryptography_public_key(public_key) @@ -153,6 +158,8 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): actual_key = self.key_mgr.get(self.context, key_id) self.assertEqual(_key, actual_key) + self.assertIsNotNone(actual_key.id) + def test_store_key_and_get_metadata(self): secret_key = bytes(b'0' * 64) _key = sym_key.SymmetricKey('AES', 64 * 8, secret_key) @@ -164,6 +171,8 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): self.assertIsNone(actual_key.get_encoded()) self.assertTrue(actual_key.is_metadata_only()) + self.assertIsNotNone(actual_key.id) + def test_store_key_and_get_metadata_and_get_key(self): secret_key = bytes(b'0' * 64) _key = sym_key.SymmetricKey('AES', 64 * 8, secret_key) @@ -181,6 +190,8 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): self.assertIsNotNone(actual_key.get_encoded()) self.assertFalse(actual_key.is_metadata_only()) + self.assertIsNotNone(actual_key.id) + def test_store_null_context(self): self.assertRaises(exception.Forbidden, self.key_mgr.store, None, None) @@ -221,6 +232,9 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): self.assertTrue(key1 in keys) self.assertTrue(key2 in keys) + for key in keys: + self.assertIsNotNone(key.id) + def test_list_keys_metadata_only(self): key1 = sym_key.SymmetricKey('AES', 64 * 8, bytes(b'0' * 64)) self.key_mgr.store(self.context, key1) @@ -233,3 +247,6 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase): for key in keys: self.assertTrue(key.is_metadata_only()) self.assertTrue(key.bit_length in bit_length_list) + + for key in keys: + self.assertIsNotNone(key.id)