diff --git a/castellan/common/objects/managed_object.py b/castellan/common/objects/managed_object.py index 58d0589..de3c2e7 100644 --- a/castellan/common/objects/managed_object.py +++ b/castellan/common/objects/managed_object.py @@ -28,11 +28,12 @@ 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 @@ -42,6 +43,17 @@ else: 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): diff --git a/castellan/common/objects/opaque_data.py b/castellan/common/objects/opaque_data.py index 81b8e45..9512ba2 100644 --- a/castellan/common/objects/opaque_data.py +++ b/castellan/common/objects/opaque_data.py @@ -25,13 +25,13 @@ 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 346d8f6..e0441b5 100644 --- a/castellan/common/objects/passphrase.py +++ b/castellan/common/objects/passphrase.py @@ -25,13 +25,13 @@ 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 45d936a..6472ef8 100644 --- a/castellan/common/objects/private_key.py +++ b/castellan/common/objects/private_key.py @@ -26,7 +26,7 @@ """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 @@ 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 6d11eb3..efcc6b5 100644 --- a/castellan/common/objects/public_key.py +++ b/castellan/common/objects/public_key.py @@ -26,7 +26,7 @@ """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 @@ 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 499c159..f9cefeb 100644 --- a/castellan/common/objects/symmetric_key.py +++ b/castellan/common/objects/symmetric_key.py @@ -26,7 +26,7 @@ """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 @@ 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 8eaa1c9..aba1a88 100644 --- a/castellan/common/objects/x_509.py +++ b/castellan/common/objects/x_509.py @@ -25,13 +25,13 @@ 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 a39116b..8b488b5 100644 --- a/castellan/key_manager/barbican_key_manager.py +++ b/castellan/key_manager/barbican_key_manager.py @@ -480,6 +480,11 @@ 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 @@ 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 f62dee3..1f8eaf6 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 @@ 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 @@ 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 @@ 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 @@ # 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 @@ # 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 @@ 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 b981292..5fee24b 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 @@ 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 5d5668c..f3fdb10 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 @@ 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 @@ 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 @@ 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 @@ 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 dd2d6e7..aef4155 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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) @@ -220,6 +231,9 @@ self.assertEqual(2, len(keys)) 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)) @@ -233,3 +247,6 @@ 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)