Codebase list python-castellan / 8f5a409
Merge tag '3.0.0' into debian/ussuri castellan 3.0.0 release meta:version: 3.0.0 meta:diff-start: - meta:series: ussuri meta:release-type: release meta:pypi: no meta:first: no meta:release:Author: Ben Nemec <bnemec@redhat.com> meta:release:Commit: Ben Nemec <bnemec@redhat.com> meta:release:Change-Id: I9ad3b891c09dab47e38de4d77dcea6d3b1516bf8 meta:release:Code-Review+2: Hervé Beraud <hberaud@redhat.com> meta:release:Code-Review+2: Sean McGinnis <sean.mcginnis@gmail.com> meta:release:Workflow+1: Sean McGinnis <sean.mcginnis@gmail.com> Thomas Goirand 4 years ago
28 changed file(s) with 266 addition(s) and 252 deletion(s). Raw diff Collapse all Expand all
5959 templates:
6060 - check-requirements
6161 - openstack-lower-constraints-jobs
62 - openstack-python-jobs
63 - openstack-python3-train-jobs
62 - openstack-python3-ussuri-jobs
6463 - periodic-stable-jobs
6564 - publish-openstack-docs-pti
6665 - release-notes-jobs-python3
88 * Source: https://opendev.org/openstack/castellan
99 * Bugs: https://bugs.launchpad.net/castellan
1010 * Release notes: https://docs.openstack.org/releasenotes/castellan
11 * Wiki: https://wiki.openstack.org/wiki/Castellan
1112
1213 Team and repository tags
1314 ========================
2222
2323 import abc
2424
25 import six
2625
27
28 @six.add_metaclass(abc.ABCMeta)
29 class Credential(object):
26 class Credential(object, metaclass=abc.ABCMeta):
3027 """Base class to represent all credentials."""
3128
3229 def __init__(self):
1616 Castellan exception subclasses
1717 """
1818
19 import six.moves.urllib.parse as urlparse
19 import urllib
2020
2121 from castellan.i18n import _
2222
2525
2626 class RedirectException(Exception):
2727 def __init__(self, url):
28 self.url = urlparse.urlparse(url)
28 self.url = urllib.parse.urlparse(url)
2929
3030
3131 class CastellanException(Exception):
1818 This module defines the Certificate class.
1919 """
2020
21 import abc
22
23 import six
24
2521 from castellan.common.objects import managed_object
2622
2723
28 @six.add_metaclass(abc.ABCMeta)
2924 class Certificate(managed_object.ManagedObject):
3025 """Base class to represent all certificates."""
2020 from Java.
2121 """
2222
23 import abc
24
2325 from castellan.common.objects import managed_object
2426
25 import abc
2627
27 import six
28
29
30 @six.add_metaclass(abc.ABCMeta)
3128 class Key(managed_object.ManagedObject):
3229 """Base class to represent all keys."""
3330
2020 """
2121 import abc
2222
23 import six
2423
25
26 @six.add_metaclass(abc.ABCMeta)
27 class ManagedObject(object):
24 class ManagedObject(object, metaclass=abc.ABCMeta):
2825 """Base class to represent all managed objects."""
2926
3027 def __init__(self, name=None, created=None, id=None):
1717 """
1818 import calendar
1919 import time
20 import urllib
2021
2122 from cryptography.hazmat import backends
2223 from cryptography.hazmat.primitives import serialization
3132 from castellan.common import exception
3233 from castellan.common.objects import key as key_base_class
3334 from castellan.common.objects import opaque_data as op_data
34 from castellan.common.objects import passphrase
35 from castellan.common.objects import private_key as pri_key
36 from castellan.common.objects import public_key as pub_key
37 from castellan.common.objects import symmetric_key as sym_key
38 from castellan.common.objects import x_509
3935 from castellan.i18n import _
4036 from castellan.key_manager import key_manager
4137
4339 from barbicanclient import client as barbican_client_import
4440 from barbicanclient import exceptions as barbican_exceptions
4541 from oslo_utils import timeutils
46 from six.moves import urllib
47
48
49 barbican_opts = [
42
43
44 _barbican_opts = [
5045 cfg.StrOpt('barbican_endpoint',
5146 help='Use this endpoint to connect to Barbican, for example: '
5247 '"http://localhost:9311/"'),
7772
7873 ]
7974
80 BARBICAN_OPT_GROUP = 'barbican'
75 _BARBICAN_OPT_GROUP = 'barbican'
8176
8277 LOG = logging.getLogger(__name__)
8378
8479
8580 class BarbicanKeyManager(key_manager.KeyManager):
8681 """Key Manager Interface that wraps the Barbican client API."""
87
88 _secret_type_dict = {
89 op_data.OpaqueData: 'opaque',
90 passphrase.Passphrase: 'passphrase',
91 pri_key.PrivateKey: 'private',
92 pub_key.PublicKey: 'public',
93 sym_key.SymmetricKey: 'symmetric',
94 x_509.X509: 'certificate'}
9582
9683 def __init__(self, configuration):
9784 self._barbican_client = None
9885 self._base_url = None
9986 self.conf = configuration
100 self.conf.register_opts(barbican_opts, group=BARBICAN_OPT_GROUP)
101 loading.register_session_conf_options(self.conf, BARBICAN_OPT_GROUP)
87 self.conf.register_opts(_barbican_opts, group=_BARBICAN_OPT_GROUP)
88 loading.register_session_conf_options(self.conf, _BARBICAN_OPT_GROUP)
10289
10390 def _get_barbican_client(self, context):
10491 """Creates a client to connect to the Barbican service.
143130 return self._barbican_client
144131
145132 def _get_keystone_auth(self, context):
146 if context.__class__.__name__ is 'KeystonePassword':
133 if context.__class__.__name__ == 'KeystonePassword':
147134 return identity.Password(
148135 auth_url=context.auth_url,
149136 username=context.username,
159146 project_domain_id=context.project_domain_id,
160147 project_domain_name=context.project_domain_name,
161148 reauthenticate=context.reauthenticate)
162 elif context.__class__.__name__ is 'KeystoneToken':
149 elif context.__class__.__name__ == 'KeystoneToken':
163150 return identity.Token(
164151 auth_url=context.auth_url,
165152 token=context.token,
173160 reauthenticate=context.reauthenticate)
174161 # this will be kept for oslo.context compatibility until
175162 # projects begin to use utils.credential_factory
176 elif context.__class__.__name__ is 'RequestContext':
177 return identity.Token(
178 auth_url=self.conf.barbican.auth_endpoint,
179 token=context.auth_token,
180 project_id=context.project_id,
181 project_name=context.project_name,
182 project_domain_id=context.project_domain_id,
183 project_domain_name=context.project_domain_name)
163 elif context.__class__.__name__ == 'RequestContext':
164 if getattr(context, 'get_auth_plugin', None):
165 return context.get_auth_plugin()
166 else:
167 return identity.Token(
168 auth_url=self.conf.barbican.auth_endpoint,
169 token=context.auth_token,
170 project_id=context.project_id,
171 project_name=context.project_name,
172 project_domain_id=context.project_domain_id,
173 project_domain_name=context.project_domain_name)
184174 else:
185175 msg = _("context must be of type KeystonePassword, "
186176 "KeystoneToken, or RequestContext.")
191181 barbican = self.conf.barbican
192182 if barbican.barbican_endpoint:
193183 return barbican.barbican_endpoint
184 elif getattr(auth, 'service_catalog', None):
185 endpoint_data = auth.service_catalog.endpoint_data_for(
186 service_type='key-manager')
187 return endpoint_data.url
194188 else:
195189 service_parameters = {'service_type': 'key-manager',
196190 'service_name': 'barbican',
198192 return auth.get_endpoint(sess, **service_parameters)
199193
200194 def _create_base_url(self, auth, sess, endpoint):
195 api_version = None
201196 if self.conf.barbican.barbican_api_version:
202197 api_version = self.conf.barbican.barbican_api_version
203 else:
198 elif getattr(auth, 'service_catalog', None):
199 endpoint_data = auth.service_catalog.endpoint_data_for(
200 service_type='key-manager')
201 api_version = endpoint_data.api_version
202 elif getattr(auth, 'get_discovery', None):
204203 discovery = auth.get_discovery(sess, url=endpoint)
205204 raw_data = discovery.raw_version_data()
206205 if len(raw_data) == 0:
621620 except (barbican_exceptions.HTTPAuthError,
622621 barbican_exceptions.HTTPClientError,
623622 barbican_exceptions.HTTPServerError) as e:
624 LOG.error(_("Error listing objects: %s"), e)
623 LOG.error("Error listing objects: %s", e)
625624 raise exception.KeyManagerError(reason=e)
626625
627626 for secret in secrets:
631630 except (barbican_exceptions.HTTPAuthError,
632631 barbican_exceptions.HTTPClientError,
633632 barbican_exceptions.HTTPServerError) as e:
634 LOG.warning(_("Error occurred while retrieving object "
635 "metadata, not adding it to the list: %s"), e)
633 LOG.warning("Error occurred while retrieving object "
634 "metadata, not adding it to the list: %s", e)
636635
637636 return objects
637
638 def list_options_for_discovery(self):
639 return [(_BARBICAN_OPT_GROUP, _barbican_opts)]
1818
1919 import abc
2020
21 import six
21 from castellan.common.objects import opaque_data as op_data
22 from castellan.common.objects import passphrase
23 from castellan.common.objects import private_key as pri_key
24 from castellan.common.objects import public_key as pub_key
25 from castellan.common.objects import symmetric_key as sym_key
26 from castellan.common.objects import x_509
2227
2328
24 @six.add_metaclass(abc.ABCMeta)
25 class KeyManager(object):
29 class KeyManager(object, metaclass=abc.ABCMeta):
2630 """Base Key Manager Interface
2731
2832 A Key Manager is responsible for managing encryption keys for volumes. A
2933 Key Manager is responsible for creating, reading, and deleting keys.
3034 """
35
36 _secret_type_dict = {
37 op_data.OpaqueData: "opaque",
38 passphrase.Passphrase: "passphrase",
39 pri_key.PrivateKey: "private",
40 pub_key.PublicKey: "public",
41 sym_key.SymmetricKey: "symmetric",
42 x_509.X509: "certificate"}
3143
3244 @abc.abstractmethod
3345 def __init__(self, configuration):
122134 found, an empty list should be returned instead.
123135 """
124136 return []
137
138 def list_options_for_discovery(self):
139 """Lists the KeyManager's configure options.
140
141 KeyManagers should advertise all supported options through this
142 method for the purpose of sample generation by oslo-config-generator.
143 Each item in the advertised list should be tuple composed by the group
144 name and a list of options belonging to that group. None should be used
145 as the group name for the DEFAULT group.
146
147 :returns: the list of supported options of a KeyManager.
148 """
149 return []
3030 from oslo_log import log as logging
3131 from oslo_utils import timeutils
3232 import requests
33 import six
3433
3534 from castellan.common import exception
36 from castellan.common.objects import opaque_data as op_data
37 from castellan.common.objects import passphrase
3835 from castellan.common.objects import private_key as pri_key
3936 from castellan.common.objects import public_key as pub_key
4037 from castellan.common.objects import symmetric_key as sym_key
41 from castellan.common.objects import x_509
4238 from castellan.i18n import _
4339 from castellan.key_manager import key_manager
4440
45 DEFAULT_VAULT_URL = "http://127.0.0.1:8200"
46 DEFAULT_MOUNTPOINT = "secret"
47
48 vault_opts = [
41 _DEFAULT_VAULT_URL = "http://127.0.0.1:8200"
42 _DEFAULT_MOUNTPOINT = "secret"
43
44 _vault_opts = [
4945 cfg.StrOpt('root_token_id',
5046 help='root token for vault'),
5147 cfg.StrOpt('approle_role_id',
5349 cfg.StrOpt('approle_secret_id',
5450 help='AppRole secret_id for authentication with vault'),
5551 cfg.StrOpt('kv_mountpoint',
56 default=DEFAULT_MOUNTPOINT,
52 default=_DEFAULT_MOUNTPOINT,
5753 help='Mountpoint of KV store in Vault to use, for example: '
58 '{}'.format(DEFAULT_MOUNTPOINT)),
54 '{}'.format(_DEFAULT_MOUNTPOINT)),
5955 cfg.StrOpt('vault_url',
60 default=DEFAULT_VAULT_URL,
56 default=_DEFAULT_VAULT_URL,
6157 help='Use this endpoint to connect to Vault, for example: '
62 '"%s"' % DEFAULT_VAULT_URL),
58 '"%s"' % _DEFAULT_VAULT_URL),
6359 cfg.StrOpt('ssl_ca_crt_file',
6460 help='Absolute path to ca cert file'),
6561 cfg.BoolOpt('use_ssl',
6763 help=_('SSL Enabled/Disabled')),
6864 ]
6965
70 VAULT_OPT_GROUP = 'vault'
66 _VAULT_OPT_GROUP = 'vault'
7167
7268 _EXCEPTIONS_BY_CODE = [
7369 requests.codes['internal_server_error'],
8379 class VaultKeyManager(key_manager.KeyManager):
8480 """Key Manager Interface that wraps the Vault REST API."""
8581
86 _secret_type_dict = {
87 op_data.OpaqueData: 'opaque',
88 passphrase.Passphrase: 'passphrase',
89 pri_key.PrivateKey: 'private',
90 pub_key.PublicKey: 'public',
91 sym_key.SymmetricKey: 'symmetric',
92 x_509.X509: 'certificate'}
93
9482 def __init__(self, configuration):
9583 self._conf = configuration
96 self._conf.register_opts(vault_opts, group=VAULT_OPT_GROUP)
97 loading.register_session_conf_options(self._conf, VAULT_OPT_GROUP)
84 self._conf.register_opts(_vault_opts, group=_VAULT_OPT_GROUP)
85 loading.register_session_conf_options(self._conf, _VAULT_OPT_GROUP)
9886 self._session = requests.Session()
9987 self._root_token_id = self._conf.vault.root_token_id
10088 self._approle_role_id = self._conf.vault.approle_role_id
173161 json=params,
174162 verify=self._verify_server)
175163 except requests.exceptions.Timeout as ex:
176 raise exception.KeyManagerError(six.text_type(ex))
164 raise exception.KeyManagerError(str(ex))
177165 except requests.exceptions.ConnectionError as ex:
178 raise exception.KeyManagerError(six.text_type(ex))
166 raise exception.KeyManagerError(str(ex))
179167 except Exception as ex:
180 raise exception.KeyManagerError(six.text_type(ex))
168 raise exception.KeyManagerError(str(ex))
181169
182170 if resp.status_code in _EXCEPTIONS_BY_CODE:
183171 raise exception.KeyManagerError(resp.reason)
199187 try:
200188 resp = method(resource, headers=headers, json=json, verify=verify)
201189 except requests.exceptions.Timeout as ex:
202 raise exception.KeyManagerError(six.text_type(ex))
190 raise exception.KeyManagerError(str(ex))
203191 except requests.exceptions.ConnectionError as ex:
204 raise exception.KeyManagerError(six.text_type(ex))
192 raise exception.KeyManagerError(str(ex))
205193 except Exception as ex:
206 raise exception.KeyManagerError(six.text_type(ex))
194 raise exception.KeyManagerError(str(ex))
207195
208196 if resp.status_code in _EXCEPTIONS_BY_CODE:
209197 raise exception.KeyManagerError(resp.reason)
215203 def create_key_pair(self, context, algorithm, length,
216204 expiration=None, name=None):
217205 """Creates an asymmetric key pair."""
218
219 # Confirm context is provided, if not raise forbidden
220 if not context:
221 msg = _("User is not authorized to use key manager.")
222 raise exception.Forbidden(msg)
223206
224207 if algorithm.lower() != 'rsa':
225208 raise NotImplementedError(
292275 def create_key(self, context, algorithm, length, name=None, **kwargs):
293276 """Creates a symmetric key."""
294277
295 # Confirm context is provided, if not raise forbidden
296 if not context:
297 msg = _("User is not authorized to use key manager.")
298 raise exception.Forbidden(msg)
299
300278 if length % 8:
301279 msg = _("Length must be multiple of 8.")
302280 raise ValueError(msg)
314292 def store(self, context, key_value, **kwargs):
315293 """Stores (i.e., registers) a key with the key manager."""
316294
317 # Confirm context is provided, if not raise forbidden
318 if not context:
319 msg = _("User is not authorized to use key manager.")
320 raise exception.Forbidden(msg)
321
322295 key_id = uuid.uuid4().hex
323296 return self._store_key_value(key_id, key_value)
324297
325298 def get(self, context, key_id, metadata_only=False):
326299 """Retrieves the key identified by the specified id."""
327
328 # Confirm context is provided, if not raise forbidden
329 if not context:
330 msg = _("User is not authorized to use key manager.")
331 raise exception.Forbidden(msg)
332300
333301 if not key_id:
334302 raise exception.KeyManagerError('key identifier not provided')
370338 def delete(self, context, key_id):
371339 """Represents deleting the key."""
372340
373 # Confirm context is provided, if not raise forbidden
374 if not context:
375 msg = _("User is not authorized to use key manager.")
376 raise exception.Forbidden(msg)
377
378341 if not key_id:
379342 raise exception.KeyManagerError('key identifier not provided')
380343
386349
387350 def list(self, context, object_type=None, metadata_only=False):
388351 """Lists the managed objects given the criteria."""
389
390 # Confirm context is provided, if not raise forbidden
391 if not context:
392 msg = _("User is not authorized to use key manager.")
393 raise exception.Forbidden(msg)
394352
395353 if object_type and object_type not in self._secret_type_dict:
396354 msg = _("Invalid secret type: %s") % object_type
411369 if object_type is None or isinstance(obj, object_type):
412370 objects.append(obj)
413371 except exception.ManagedObjectNotFoundError as e:
414 LOG.warning(_("Error occurred while retrieving object "
415 "metadata, not adding it to the list: %s"), e)
372 LOG.warning("Error occurred while retrieving object "
373 "metadata, not adding it to the list: %s", e)
416374 pass
417375 return objects
376
377 def list_options_for_discovery(self):
378 return [(_VAULT_OPT_GROUP, _vault_opts)]
1111 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1212 # License for the specific language governing permissions and limitations
1313 # under the License.
14 from stevedore import ExtensionManager
15
1416 from oslo_config import cfg
1517 from oslo_log import log
1618
17 from castellan import key_manager as km
19 from castellan import key_manager
1820 try:
1921 from castellan.key_manager import barbican_key_manager as bkm
2022 except ImportError:
6567 :param barbican_endpoint_type: Use this to specify the type of URL.
6668 : Valid values are: public, internal or admin.
6769 """
68 conf.register_opts(km.key_manager_opts, group='key_manager')
69 if bkm:
70 conf.register_opts(bkm.barbican_opts, group=bkm.BARBICAN_OPT_GROUP)
71 if vkm:
72 conf.register_opts(vkm.vault_opts, group=vkm.VAULT_OPT_GROUP)
70 conf.register_opts(key_manager.key_manager_opts, group='key_manager')
71
72 ext_mgr = ExtensionManager(
73 "castellan.drivers",
74 invoke_on_load=True,
75 invoke_args=[cfg.CONF])
76
77 for km in ext_mgr.names():
78 for group, opts in ext_mgr[km].obj.list_options_for_discovery():
79 conf.register_opts(opts, group=group)
7380
7481 # Use the new backend option if set or fall back to the older api_class
7582 default_backend = backend or api_class
7986 if bkm is not None:
8087 if barbican_endpoint is not None:
8188 conf.set_default('barbican_endpoint', barbican_endpoint,
82 group=bkm.BARBICAN_OPT_GROUP)
89 group=bkm._BARBICAN_OPT_GROUP)
8390 if barbican_api_version is not None:
8491 conf.set_default('barbican_api_version', barbican_api_version,
85 group=bkm.BARBICAN_OPT_GROUP)
92 group=bkm._BARBICAN_OPT_GROUP)
8693 if auth_endpoint is not None:
8794 conf.set_default('auth_endpoint', auth_endpoint,
88 group=bkm.BARBICAN_OPT_GROUP)
95 group=bkm._BARBICAN_OPT_GROUP)
8996 if retry_delay is not None:
9097 conf.set_default('retry_delay', retry_delay,
91 group=bkm.BARBICAN_OPT_GROUP)
98 group=bkm._BARBICAN_OPT_GROUP)
9299 if number_of_retries is not None:
93100 conf.set_default('number_of_retries', number_of_retries,
94 group=bkm.BARBICAN_OPT_GROUP)
101 group=bkm._BARBICAN_OPT_GROUP)
95102 if verify_ssl is not None:
96103 conf.set_default('verify_ssl', verify_ssl,
97 group=bkm.BARBICAN_OPT_GROUP)
104 group=bkm._BARBICAN_OPT_GROUP)
98105 if barbican_endpoint_type is not None:
99106 conf.set_default('barbican_endpoint_type', barbican_endpoint_type,
100 group=bkm.BARBICAN_OPT_GROUP)
107 group=bkm._BARBICAN_OPT_GROUP)
101108
102109 if vkm is not None:
103110 if vault_root_token_id is not None:
150157 :returns: a list of (group_name, opts) tuples
151158 """
152159 key_manager_opts = []
153 key_manager_opts.extend(km.key_manager_opts)
160 key_manager_opts.extend(key_manager.key_manager_opts)
154161 key_manager_opts.extend(utils.credential_opts)
155162 opts = [('key_manager', key_manager_opts)]
156163
157 if bkm is not None:
158 opts.append((bkm.BARBICAN_OPT_GROUP, bkm.barbican_opts))
159 if vkm is not None:
160 opts.append((vkm.VAULT_OPT_GROUP, vkm.vault_opts))
164 ext_mgr = ExtensionManager(
165 "castellan.drivers",
166 invoke_on_load=True,
167 invoke_args=[cfg.CONF])
168
169 for driver in ext_mgr.names():
170 opts.extend(ext_mgr[driver].obj.list_options_for_discovery())
171
161172 return opts
7676 def setUp(self):
7777 super(KeyManagerTestCase, self).setUp()
7878 self.key_mgr = self._create_key_manager()
79 self.ctxt = None
7980
8081 def _get_valid_object_uuid(self, managed_object):
8182 object_uuid = self.key_mgr.store(self.ctxt, managed_object)
1414
1515 Note: This requires local running instance of Vault.
1616 """
17 import abc
1817 import os
1918 import uuid
2019
2120 from oslo_config import cfg
22 from oslo_context import context
2321 from oslo_utils import uuidutils
2422 from oslotest import base
2523 import requests
3331 CONF = config.get_config()
3432
3533
36 class VaultKeyManagerTestCase(test_key_manager.KeyManagerTestCase):
34 class VaultKeyManagerTestCase(test_key_manager.KeyManagerTestCase,
35 base.BaseTestCase):
3736 def _create_key_manager(self):
3837 key_mgr = vault_key_manager.VaultKeyManager(cfg.CONF)
3938
4544 key_mgr._vault_url = os.environ['VAULT_TEST_URL']
4645 return key_mgr
4746
48 @abc.abstractmethod
49 def get_context(self):
50 """Retrieves Context for Authentication"""
51 return
52
53 def setUp(self):
54 super(VaultKeyManagerTestCase, self).setUp()
55 self.ctxt = self.get_context()
56
57 def tearDown(self):
58 super(VaultKeyManagerTestCase, self).tearDown()
59
60 def test_create_null_context(self):
61 self.assertRaises(exception.Forbidden,
62 self.key_mgr.create_key, None, 'AES', 256)
63
64 def test_create_key_pair_null_context(self):
65 self.assertRaises(exception.Forbidden,
66 self.key_mgr.create_key_pair, None, 'RSA', 2048)
67
6847 def test_create_key_pair_bad_algorithm(self):
6948 self.assertRaises(
7049 NotImplementedError,
7251 self.ctxt, 'DSA', 2048
7352 )
7453
75 def test_delete_null_context(self):
76 key_uuid = self._get_valid_object_uuid(
77 test_key_manager._get_test_symmetric_key())
78 self.addCleanup(self.key_mgr.delete, self.ctxt, key_uuid)
79 self.assertRaises(exception.Forbidden,
80 self.key_mgr.delete, None, key_uuid)
81
8254 def test_delete_null_object(self):
8355 self.assertRaises(exception.KeyManagerError,
8456 self.key_mgr.delete, self.ctxt, None)
85
86 def test_get_null_context(self):
87 key_uuid = self._get_valid_object_uuid(
88 test_key_manager._get_test_symmetric_key())
89 self.addCleanup(self.key_mgr.delete, self.ctxt, key_uuid)
90 self.assertRaises(exception.Forbidden,
91 self.key_mgr.get, None, key_uuid)
9257
9358 def test_get_null_object(self):
9459 self.assertRaises(exception.KeyManagerError,
9863 bad_key_uuid = uuidutils.generate_uuid()
9964 self.assertRaises(exception.ManagedObjectNotFoundError,
10065 self.key_mgr.get, self.ctxt, bad_key_uuid)
101
102 def test_store_null_context(self):
103 key = test_key_manager._get_test_symmetric_key()
104
105 self.assertRaises(exception.Forbidden,
106 self.key_mgr.store, None, key)
107
108
109 class VaultKeyManagerOSLOContextTestCase(VaultKeyManagerTestCase,
110 base.BaseTestCase):
111 def get_context(self):
112 return context.get_admin_context()
11366
11467
11568 TEST_POLICY = '''
12780 APPROLE_ENDPOINT = 'v1/auth/approle/role/{role_name}'
12881
12982
130 class VaultKeyManagerAppRoleTestCase(VaultKeyManagerOSLOContextTestCase):
83 class VaultKeyManagerAppRoleTestCase(VaultKeyManagerTestCase):
13184
13285 mountpoint = 'secret'
13386
9393 endpoint)
9494 self.assertEqual(endpoint + "/" + version, base_url)
9595
96 def test_base_url_service_catalog(self):
97 endpoint_data = mock.Mock()
98 endpoint_data.api_version = 'v321'
99
100 auth = mock.Mock(spec=['service_catalog'])
101 auth.service_catalog.endpoint_data_for.return_value = endpoint_data
102
103 endpoint = "http://localhost/key_manager"
104
105 base_url = self.key_mgr._create_base_url(auth,
106 mock.Mock(),
107 endpoint)
108 self.assertEqual(endpoint + "/" + endpoint_data.api_version, base_url)
109 auth.service_catalog.endpoint_data_for.assert_called_once_with(
110 service_type='key-manager')
111
112 def test_base_url_raise_exception(self):
113 auth = mock.Mock(spec=['get_discovery'])
114 sess = mock.Mock()
115 discovery = mock.Mock()
116 discovery.raw_version_data = mock.Mock(return_value=[])
117 auth.get_discovery = mock.Mock(return_value=discovery)
118
119 endpoint = "http://localhost/key_manager"
120
121 self.assertRaises(exception.KeyManagerError,
122 self.key_mgr._create_base_url,
123 auth, sess, endpoint)
124 auth.get_discovery.asser_called_once_with(sess, url=endpoint)
125 self.assertEqual(1, discovery.raw_version_data.call_count)
126
127 def test_base_url_get_discovery(self):
128 version = 'v100500'
129 auth = mock.Mock(spec=['get_discovery'])
130 sess = mock.Mock()
131 discovery = mock.Mock()
132 auth.get_discovery = mock.Mock(return_value=discovery)
133 discovery.raw_version_data = mock.Mock(return_value=[{'id': version}])
134
135 endpoint = "http://localhost/key_manager"
136
137 base_url = self.key_mgr._create_base_url(auth,
138 mock.Mock(),
139 endpoint)
140 self.assertEqual(endpoint + "/" + version, base_url)
141 auth.get_discovery.asser_called_once_with(sess, url=endpoint)
142 self.assertEqual(1, discovery.raw_version_data.call_count)
143
96144 def test_create_key(self):
97145 # Create order_ref_url and assign return value
98146 order_ref_url = ("http://localhost:9311/v1/orders/"
3939 barbican_endpoint = 'http://test-server.org:9311/'
4040 options.set_defaults(conf, barbican_endpoint=barbican_endpoint)
4141 self.assertEqual(barbican_endpoint,
42 conf.get(bkm.BARBICAN_OPT_GROUP).barbican_endpoint)
42 conf.barbican.barbican_endpoint)
4343
4444 barbican_api_version = 'vSomething'
4545 options.set_defaults(conf, barbican_api_version=barbican_api_version)
4646 self.assertEqual(barbican_api_version,
47 conf.get(bkm.BARBICAN_OPT_GROUP).barbican_api_version)
47 conf.barbican.barbican_api_version)
4848
4949 auth_endpoint = 'http://test-server.org/identity'
5050 options.set_defaults(conf, auth_endpoint=auth_endpoint)
5151 self.assertEqual(auth_endpoint,
52 conf.get(bkm.BARBICAN_OPT_GROUP).auth_endpoint)
52 conf.barbican.auth_endpoint)
5353
5454 retry_delay = 3
5555 options.set_defaults(conf, retry_delay=retry_delay)
5656 self.assertEqual(retry_delay,
57 conf.get(bkm.BARBICAN_OPT_GROUP).retry_delay)
57 conf.barbican.retry_delay)
5858
5959 number_of_retries = 10
6060 options.set_defaults(conf, number_of_retries=number_of_retries)
6161 self.assertEqual(number_of_retries,
62 conf.get(bkm.BARBICAN_OPT_GROUP).number_of_retries)
62 conf.barbican.number_of_retries)
6363
6464 verify_ssl = True
6565 options.set_defaults(conf, verify_ssl=True)
6666 self.assertEqual(verify_ssl,
67 conf.get(bkm.BARBICAN_OPT_GROUP).verify_ssl)
67 conf.barbican.verify_ssl)
6868
6969 barbican_endpoint_type = 'internal'
7070 options.set_defaults(conf, barbican_endpoint_type='internal')
71 result_type = conf.get(bkm.BARBICAN_OPT_GROUP).barbican_endpoint_type
71 result_type = conf.barbican.barbican_endpoint_type
7272 self.assertEqual(barbican_endpoint_type, result_type)
1818 import functools
1919 import types
2020
21 import six
22
2321
2422 def construct_new_test_function(original_func, name, build_params):
2523 """Builds a new test function based on parameterized data.
3129 :return: A new function object
3230 """
3331 new_func = types.FunctionType(
34 six.get_function_code(original_func),
35 six.get_function_globals(original_func),
32 original_func.__code__,
33 original_func.__globals__,
3634 name=name,
37 argdefs=six.get_function_defaults(original_func)
35 argdefs=original_func.__defaults__,
3836 )
3937
4038 for key, val in original_func.__dict__.items():
0 sphinx>=1.8.0,!=2.1.0 # BSD
1 sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
2 reno>=2.5.0 # Apache-2.0
3 openstackdocstheme>=1.18.1 # Apache-2.0
2222 'sphinx.ext.autodoc',
2323 #'sphinx.ext.intersphinx',
2424 'openstackdocstheme',
25 'sphinxcontrib.rsvgconverter',
2526 ]
2627
2728 # autodoc generation is a bit aggressive and a nuisance when doing heavy
7071 # Grouping the document tree into LaTeX files. List of tuples
7172 # (source start file, target name, title, author, documentclass
7273 # [howto/manual]).
74
7375 latex_documents = [
7476 ('index',
75 '%s.tex' % project,
77 'doc-castellan.tex',
7678 u'%s Documentation' % project,
7779 u'OpenStack Foundation', 'manual'),
7880 ]
81
82 latex_elements = {
83 'extraclassoptions': 'openany,oneside',
84 }
85
86 latex_use_xindy = False
7987
8088 # Example configuration for intersphinx: refer to the Python standard library.
8189 #intersphinx_mapping = {'https://docs.python.org/3/': None}
1414 user/index
1515 contributor/index
1616
17 Indices and tables
18 ==================
17 .. only:: html
1918
20 * :ref:`genindex`
21 * :ref:`modindex`
22 * :ref:`search`
19 Indices and tables
20 ==================
2321
22 * :ref:`genindex`
23 * :ref:`modindex`
24 * :ref:`search`
1616 gitdb==0.6.4
1717 GitPython==1.0.1
1818 hacking==0.12.0
19 idna==2.6
19 idna==2.5
2020 imagesize==0.7.1
2121 iso8601==0.1.11
2222 Jinja2==2.10
3030 msgpack-python==0.4.0
3131 netaddr==0.7.18
3232 netifaces==0.10.4
33 openstackdocstheme==1.18.1
3433 os-client-config==1.28.0
3534 oslo.config==6.4.0
3635 oslo.context==2.19.2
5554 python-subunit==1.0.0
5655 pytz==2013.6
5756 PyYAML==3.12
58 reno==2.5.0
59 requests==2.14.2
57 requests==2.18.0
6058 requestsexceptions==1.2.0
6159 rfc3986==0.3.1
62 six==1.10.0
6360 smmap==0.9.0
6461 snowballstemmer==1.2.1
65 Sphinx==1.6.2
66 sphinxcontrib-websupport==1.0.1
6762 stevedore==1.20.0
6863 stestr==2.0.0
6964 testscenarios==0.4
0 ---
1 upgrade:
2 - |
3 Python 2.7 support has been dropped. The minimum version of Python now
4 supported by castellan is Python 3.6.
0 ---
1 features:
2 - |
3 Enhance the global option listing to discover available key managers and
4 their options. The purpose of this feature is to have a correct listing of
5 the supported key managers, now each key manager is responsible for
6 advertising the oslo.config groups/options they consume.
7 other:
8 - |
9 The visibility of module variables and constants related to oslo.config
10 options changed to private in both barbican and vault key managers. The
11 key managers are only responsible for overloading the method
12 list_options_for_discovery() in order to advertise their own options.
13 This way, the global options doesn't need to know which variables to look
14 for.
55 :maxdepth: 1
66
77 unreleased
8 train
89 stein
910 rocky
1011 queens
0 ==========================
1 Train Series Release Notes
2 ==========================
3
4 .. release-notes::
5 :branch: stable/train
1212 oslo.utils>=3.33.0 # Apache-2.0
1313 stevedore>=1.20.0 # Apache-2.0
1414 keystoneauth1>=3.4.0 # Apache-2.0
15 requests>=2.14.2,!=2.20.0 # Apache-2.0
15 requests>=2.18.0,!=2.20.0 # Apache-2.0
55 author = OpenStack
66 author-email = openstack-discuss@lists.openstack.org
77 home-page = https://docs.openstack.org/castellan/latest/
8 python-requires = >=3.6
89 classifier =
910 Environment :: OpenStack
1011 Intended Audience :: Information Technology
1213 License :: OSI Approved :: Apache Software License
1314 Operating System :: POSIX :: Linux
1415 Programming Language :: Python
15 Programming Language :: Python :: 2
16 Programming Language :: Python :: 2.7
1716 Programming Language :: Python :: 3
1817 Programming Language :: Python :: 3.6
1918 Programming Language :: Python :: 3.7
19 Programming Language :: Python :: 3 :: Only
20 Programming Language :: Python :: Implementation :: CPython
2021
2122 [files]
2223 packages =
3435 barbican = castellan.key_manager.barbican_key_manager:BarbicanKeyManager
3536 vault = castellan.key_manager.vault_key_manager:VaultKeyManager
3637
37 [build_sphinx]
38 source-dir = doc/source
39 build-dir = doc/build
40 all_files = 1
41 warning-is-error = 1
42
43 [upload_sphinx]
44 upload-dir = doc/build/html
45
4638 [compile_catalog]
4739 directory = castellan/locale
4840 domain = castellan
5648 keywords = _ gettext ngettext l_ lazy_gettext
5749 mapping_file = babel.cfg
5850 output_file = castellan/locale/castellan.pot
59
60 [wheel]
61 universal = 1
55 coverage!=4.4,>=4.0 # Apache-2.0
66 python-barbicanclient>=4.5.2 # Apache-2.0
77 python-subunit>=1.0.0 # Apache-2.0/BSD
8 sphinx!=1.6.6,!=1.6.7,>=1.6.2,<2.0.0;python_version=='2.7' # BSD
9 sphinx!=1.6.6,!=1.6.7,>=1.6.2;python_version>='3.4' # BSD
10 openstackdocstheme>=1.18.1 # Apache-2.0
118 oslotest>=3.2.0 # Apache-2.0
129 stestr>=2.0.0 # Apache-2.0
1310 fixtures>=3.0.0 # Apache-2.0/BSD
1411 testscenarios>=0.4 # Apache-2.0/BSD
1512 testtools>=2.2.0 # MIT
1613 bandit>=1.1.0,<1.6.0 # Apache-2.0
17 reno>=2.5.0 # Apache-2.0
1814 pifpaf>=0.10.0 # Apache-2.0
00 [tox]
1 minversion = 2.0
2 envlist = py27,py37,pep8
1 minversion = 3.1.1
2 envlist = py37,pep8
3 ignore_basepython_conflict = True
34 skipsdist = True
45
56 [testenv]
67 usedevelop = True
7 install_command = pip install {opts} {packages}
8 basepython = python3
89 setenv =
910 VIRTUAL_ENV={envdir}
1011 OS_TEST_PATH=./castellan/tests/unit
1415 -r{toxinidir}/test-requirements.txt
1516 commands = stestr run --slowest {posargs}
1617
17 [testenv:py27]
18 basepython = python2.7
19
2018 [testenv:pep8]
21 basepython = python3
2219 commands =
2320 flake8
2421 bandit -r castellan -x tests -s B105,B106,B107,B607
2522
2623 [testenv:bandit]
27 basepython = python3
2824 # This command runs the bandit security linter against the castellan
2925 # codebase minus the tests directory. Some tests are being excluded to
3026 # reduce the number of positives before a team inspection, and to ensure a
3733 bandit -r castellan -x tests -s B105,B106,B107,B607
3834
3935 [testenv:venv]
40 basepython = python3
4136 commands = {posargs}
4237
4338 [testenv:debug]
44 basepython = python3
4539 commands = oslo_debug_helper {posargs}
4640
4741 [testenv:cover]
48 basepython = python3
4942 setenv =
50 PYTHON=coverage run --source $project --parallel-mode
43 PYTHON=coverage run --source castellan --parallel-mode
5144 commands =
52 stestr run {posargs}
45 coverage erase
46 {[testenv]commands}
5347 coverage combine
5448 coverage html -d cover
5549 coverage xml -o cover/coverage.xml
56 coverage report
50 coverage report --show-missing
5751
5852 [testenv:docs]
59 basepython = python3
60 commands = python setup.py build_sphinx
53 # This environment is called from CI scripts to test and publish
54 # the main docs to https://docs.openstack.org/castellan
55 description = Build main documentation
56 deps = -r{toxinidir}/doc/requirements.txt
57 commands=
58 rm -rf doc/build doc/build/doctrees
59 sphinx-build -W -b html -d doc/build/doctrees doc/source doc/build/html
60 whitelist_externals = rm
61
62 [testenv:pdf-docs]
63 deps = {[testenv:docs]deps}
64 envdir = {toxworkdir}/docs
65 whitelist_externals =
66 rm
67 make
68 commands =
69 rm -rf doc/build/pdf
70 sphinx-build -W -b latex doc/source doc/build/pdf
71 make -C doc/build/pdf
6172
6273 [testenv:releasenotes]
63 basepython = python3
74 deps = {[testenv:docs]deps}
75 envdir = {toxworkdir}/docs
6476 commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
6577
6678 [testenv:functional]
8294 {toxinidir}/tools/setup-vault-env.sh pifpaf -e VAULT_TEST run vault -- stestr run --slowest {posargs}
8395
8496 [testenv:genconfig]
85 basepython = python3
8697 commands =
8798 oslo-config-generator --config-file=etc/castellan/functional-config-generator.conf
8899 oslo-config-generator --config-file=etc/castellan/sample-config-generator.conf
98109 import_exceptions = castellan.i18n
99110
100111 [testenv:lower-constraints]
101 basepython = python3
102112 deps =
103113 -c{toxinidir}/lower-constraints.txt
104114 -r{toxinidir}/test-requirements.txt
105115 -r{toxinidir}/requirements.txt
106116
107117 [testenv:bindep]
108 basepython = python3
109118 # Do not install any requirements. We want this to be fast and work even if
110119 # system dependencies are missing, since it's used to tell you what system
111120 # dependencies are missing! This also means that bindep must be installed