Merge "Synchronize the key manager interface with Cinder"
This commit is contained in:
@@ -977,7 +977,7 @@
|
||||
|
||||
# The full class name of the key manager API class (string
|
||||
# value)
|
||||
#keymgr_api_class=nova.keymgr.key_mgr.KeyManager
|
||||
#keymgr_api_class=nova.keymgr.not_implemented_key_mgr.NotImplementedKeyManager
|
||||
|
||||
|
||||
#
|
||||
|
@@ -21,7 +21,8 @@ from nova.openstack.common import log as logging
|
||||
|
||||
keymgr_opts = [
|
||||
cfg.StrOpt('keymgr_api_class',
|
||||
default='nova.keymgr.key_mgr.KeyManager',
|
||||
default='nova.keymgr.'
|
||||
'not_implemented_key_mgr.NotImplementedKeyManager',
|
||||
help='The full class name of the key manager API class'),
|
||||
]
|
||||
|
||||
|
@@ -33,15 +33,18 @@ class Key(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_algorithm(self):
|
||||
"""Returns this key's algorithm. For example, "DSA" would indicate
|
||||
that this key is a DSA key.
|
||||
"""Returns the key's algorithm.
|
||||
|
||||
Returns the key's algorithm. For example, "DSA" indicates that this key
|
||||
is a DSA key and "AES" indicates that this key is an AES key.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_format(self):
|
||||
"""Returns the encoding format of this key or None if this key is not
|
||||
encoded.
|
||||
"""Returns the encoding format.
|
||||
|
||||
Returns the key's encoding format or None if this key is not encoded.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -57,8 +60,10 @@ class SymmetricKey(Key):
|
||||
"""
|
||||
|
||||
def __init__(self, alg, key):
|
||||
"""Create a new SymmetricKey object. This specifies the algorithm for
|
||||
the symmetric encryption and the bytes for the key.
|
||||
"""Create a new SymmetricKey object.
|
||||
|
||||
The arguments specify the algorithm for the symmetric encryption and
|
||||
the bytes for the key.
|
||||
"""
|
||||
self.alg = alg
|
||||
self.key = key
|
||||
@@ -68,7 +73,7 @@ class SymmetricKey(Key):
|
||||
return self.alg
|
||||
|
||||
def get_format(self):
|
||||
"""This returns 'RAW'."""
|
||||
"""This method returns 'RAW'."""
|
||||
return "RAW"
|
||||
|
||||
def get_encoded(self):
|
||||
|
@@ -52,6 +52,21 @@ class KeyManager(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def copy_key(self, ctxt, key_id, **kwargs):
|
||||
"""Copies (i.e., clones) a key stored by the key manager.
|
||||
|
||||
This method copies the specified key and returns the copy's UUID. If
|
||||
the specified context does not permit copying keys, then a
|
||||
NotAuthorized error should be raised.
|
||||
|
||||
Implementation note: This method should behave identically to
|
||||
store_key(context, get_key(context, <encryption key UUID>))
|
||||
although it is preferable to perform this operation within the key
|
||||
manager to avoid unnecessary handling of the key material.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_key(self, ctxt, key_id, **kwargs):
|
||||
"""Retrieves the specified key.
|
||||
|
42
nova/keymgr/not_implemented_key_mgr.py
Normal file
42
nova/keymgr/not_implemented_key_mgr.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Key manager implementation that raises NotImplementedError
|
||||
"""
|
||||
|
||||
from nova.keymgr import key_mgr
|
||||
|
||||
|
||||
class NotImplementedKeyManager(key_mgr.KeyManager):
|
||||
"""Key Manager Interface that raises NotImplementedError for all operations
|
||||
"""
|
||||
|
||||
def create_key(self, ctxt, algorithm='AES', length=256, expiration=None,
|
||||
**kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def store_key(self, ctxt, key, expiration=None, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def copy_key(self, ctxt, key_id, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_key(self, ctxt, key_id, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete_key(self, ctxt, key_id, **kwargs):
|
||||
raise NotImplementedError()
|
26
nova/tests/keymgr/fake.py
Normal file
26
nova/tests/keymgr/fake.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 Justin Santa Barbara
|
||||
# Copyright 2012 OpenStack LLC
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Implementation of a fake key manager."""
|
||||
|
||||
|
||||
from nova.tests.keymgr import mock_key_mgr
|
||||
|
||||
|
||||
def fake_api():
|
||||
return mock_key_mgr.MockKeyManager()
|
@@ -20,12 +20,12 @@ anything but integration testing.
|
||||
"""
|
||||
|
||||
import array
|
||||
import uuid
|
||||
|
||||
from nova import exception
|
||||
from nova.keymgr import key
|
||||
from nova.keymgr import key_mgr
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common import uuidutils
|
||||
from nova import utils
|
||||
|
||||
|
||||
@@ -35,15 +35,15 @@ LOG = logging.getLogger(__name__)
|
||||
class MockKeyManager(key_mgr.KeyManager):
|
||||
"""
|
||||
This mock key manager implementation supports all the methods specified
|
||||
by the key manager interface. This implementation creates a single key in
|
||||
response to all invocations of create_key. Side effects (e.g., raising
|
||||
exceptions) for each method are handled as specified by the key manager
|
||||
interface.
|
||||
by the key manager interface. This implementation stores keys within a
|
||||
dictionary, and as a result, it is not acceptable for use across different
|
||||
services. Side effects (e.g., raising exceptions) for each method are
|
||||
handled as specified by the key manager interface.
|
||||
|
||||
This class should NOT be used for anything but integration testing because
|
||||
the same key is created for all invocations of create_key and keys are not
|
||||
stored persistently.
|
||||
keys are not stored persistently.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.keys = {}
|
||||
|
||||
@@ -67,6 +67,13 @@ class MockKeyManager(key_mgr.KeyManager):
|
||||
|
||||
return self.store_key(ctxt, _key)
|
||||
|
||||
def _generate_key_id(self):
|
||||
key_id = uuidutils.generate_uuid()
|
||||
while key_id in self.keys:
|
||||
key_id = uuidutils.generate_uuid()
|
||||
|
||||
return key_id
|
||||
|
||||
def store_key(self, ctxt, key, **kwargs):
|
||||
"""Stores (i.e., registers) a key with the key manager.
|
||||
|
||||
@@ -76,22 +83,26 @@ class MockKeyManager(key_mgr.KeyManager):
|
||||
if ctxt is None:
|
||||
raise exception.NotAuthorized()
|
||||
|
||||
# generate UUID and ensure that it isn't in use
|
||||
key_id = uuid.uuid4()
|
||||
while key_id in self.keys:
|
||||
key_id = uuid.uuid4()
|
||||
|
||||
key_id = self._generate_key_id()
|
||||
self.keys[key_id] = key
|
||||
|
||||
return key_id
|
||||
|
||||
def copy_key(self, ctxt, key_id, **kwargs):
|
||||
if ctxt is None:
|
||||
raise exception.NotAuthorized()
|
||||
|
||||
copied_key_id = self._generate_key_id()
|
||||
self.keys[copied_key_id] = self.keys[key_id]
|
||||
|
||||
return copied_key_id
|
||||
|
||||
def get_key(self, ctxt, key_id, **kwargs):
|
||||
"""Retrieves the key identified by the specified id.
|
||||
|
||||
This implementation returns a fixed key that is associated with the
|
||||
UUID returned by the create_key method. A NotAuthorized exception is
|
||||
raised if the specified context is None; a KeyError is raised if the
|
||||
UUID is invalid.
|
||||
This implementation returns the key that is associated with the
|
||||
specified UUID. A NotAuthorized exception is raised if the specified
|
||||
context is None; a KeyError is raised if the UUID is invalid.
|
||||
"""
|
||||
if ctxt is None:
|
||||
raise exception.NotAuthorized()
|
||||
@@ -101,9 +112,8 @@ class MockKeyManager(key_mgr.KeyManager):
|
||||
def delete_key(self, ctxt, key_id, **kwargs):
|
||||
"""Deletes the key identified by the specified id.
|
||||
|
||||
This implementation intentionally does nothing except raise a
|
||||
NotAuthorized exception is the context is None or a KeyError if the
|
||||
UUID is invalid.
|
||||
A NotAuthorized exception is raised if the context is None and a
|
||||
KeyError is raised if the UUID is invalid.
|
||||
"""
|
||||
if ctxt is None:
|
||||
raise exception.NotAuthorized()
|
||||
|
@@ -22,7 +22,7 @@ import array
|
||||
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova.keymgr import key
|
||||
from nova.keymgr import key as keymgr_key
|
||||
from nova.tests.keymgr import mock_key_mgr
|
||||
from nova.tests.keymgr import test_key_mgr
|
||||
|
||||
@@ -54,8 +54,8 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
|
||||
self.key_mgr.create_key, None)
|
||||
|
||||
def test_store_key(self):
|
||||
_key = key.SymmetricKey('AES',
|
||||
array.array('B', ('0' * 64).decode('hex')).tolist())
|
||||
secret_key = array.array('B', ('0' * 64).decode('hex')).tolist()
|
||||
_key = keymgr_key.SymmetricKey('AES', secret_key)
|
||||
key_id = self.key_mgr.store_key(self.ctxt, _key)
|
||||
|
||||
actual_key = self.key_mgr.get_key(self.ctxt, key_id)
|
||||
@@ -65,6 +65,20 @@ class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
|
||||
self.assertRaises(exception.NotAuthorized,
|
||||
self.key_mgr.store_key, None, None)
|
||||
|
||||
def test_copy_key(self):
|
||||
key_id = self.key_mgr.create_key(self.ctxt)
|
||||
key = self.key_mgr.get_key(self.ctxt, key_id)
|
||||
|
||||
copied_key_id = self.key_mgr.copy_key(self.ctxt, key_id)
|
||||
copied_key = self.key_mgr.get_key(self.ctxt, copied_key_id)
|
||||
|
||||
self.assertNotEqual(key_id, copied_key_id)
|
||||
self.assertEqual(key, copied_key)
|
||||
|
||||
def test_copy_null_context(self):
|
||||
self.assertRaises(exception.NotAuthorized,
|
||||
self.key_mgr.copy_key, None, None)
|
||||
|
||||
def test_get_key(self):
|
||||
pass
|
||||
|
||||
|
51
nova/tests/keymgr/test_not_implemented_key_mgr.py
Normal file
51
nova/tests/keymgr/test_not_implemented_key_mgr.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Test cases for the not implemented key manager.
|
||||
"""
|
||||
|
||||
from nova.keymgr import not_implemented_key_mgr
|
||||
from nova.tests.keymgr import test_key_mgr
|
||||
|
||||
|
||||
class NotImplementedKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
|
||||
|
||||
def _create_key_manager(self):
|
||||
return not_implemented_key_mgr.NotImplementedKeyManager()
|
||||
|
||||
def setUp(self):
|
||||
super(NotImplementedKeyManagerTestCase, self).setUp()
|
||||
|
||||
def test_create_key(self):
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.key_mgr.create_key, None)
|
||||
|
||||
def test_store_key(self):
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.key_mgr.store_key, None, None)
|
||||
|
||||
def test_copy_key(self):
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.key_mgr.copy_key, None, None)
|
||||
|
||||
def test_get_key(self):
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.key_mgr.get_key, None, None)
|
||||
|
||||
def test_delete_key(self):
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.key_mgr.delete_key, None, None)
|
Reference in New Issue
Block a user