Add functional tests for Barbican key manager wrapper
Creates the initial functional testing infrastructure for Castellan.
Functional tests are run using:
tox -e functional
The Barbican wrapper tests require running local Barbican and Keystone
instances.
The functional testing config parameters can be overwritten by creating a
config file at /etc/castellan/castellan-functional.conf. A sample config
can be generated using:
tox -e genconfig
The generated sample config can be found at etc/castellan/castellan-functional.conf
Implements: blueprint add-barbican-key-manager
Change-Id: Ideb9b1f01e51d85ff56575d8ab6ac970053a9604
Kaitlin Farr
8 years ago
19 | 19 | |
20 | 20 | class TestCase(base.BaseTestCase): |
21 | 21 | |
22 | """Test case base class for all unit tests.""" | |
22 | """Test case base class for all tests.""" |
0 | # Copyright (c) The Johns Hopkins University/Applied Physics Laboratory | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | import os | |
16 | ||
17 | from oslo_config import cfg | |
18 | ||
19 | TEST_CONF = None | |
20 | ||
21 | identity_group = cfg.OptGroup(name='identity') | |
22 | identity_options = [ | |
23 | cfg.StrOpt('uri', | |
24 | default='http://localhost:5000/v3', | |
25 | help='Keystone endpoint'), | |
26 | cfg.StrOpt('username', | |
27 | default='admin', | |
28 | help='Keystone username'), | |
29 | cfg.StrOpt('password', | |
30 | default='secretadmin', | |
31 | help='Password used with Keystone username'), | |
32 | cfg.StrOpt('project_name', | |
33 | default='admin', | |
34 | help='Name of project, used by the given username')] | |
35 | ||
36 | ||
37 | def setup_config(config_file=''): | |
38 | global TEST_CONF | |
39 | TEST_CONF = cfg.ConfigOpts() | |
40 | ||
41 | TEST_CONF.register_group(identity_group) | |
42 | TEST_CONF.register_opts(identity_options, group=identity_group) | |
43 | ||
44 | config_to_load = [] | |
45 | local_config = './../../../etc/castellan/castellan-functional.conf' | |
46 | if os.path.isfile(config_file): | |
47 | config_to_load.append(config_file) | |
48 | elif os.path.isfile(local_config): | |
49 | config_to_load.append(local_config) | |
50 | else: | |
51 | config_to_load.append('/etc/castellan/castellan-functional.conf') | |
52 | ||
53 | TEST_CONF( | |
54 | (), # Required to load an anonymous config | |
55 | default_config_files=config_to_load | |
56 | ) | |
57 | ||
58 | ||
59 | def get_config(): | |
60 | if not TEST_CONF: | |
61 | setup_config() | |
62 | return TEST_CONF | |
63 | ||
64 | ||
65 | def list_opts(): | |
66 | yield identity_group.name, identity_options |
0 | # Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Functional test cases for the Barbican key manager. | |
17 | ||
18 | Note: This requires local running instances of Barbican and Keystone. | |
19 | """ | |
20 | ||
21 | import uuid | |
22 | ||
23 | from barbicanclient import exceptions as barbican_exceptions | |
24 | from keystoneclient.v3 import client | |
25 | from oslo_context import context | |
26 | ||
27 | from castellan.common import exception | |
28 | from castellan.key_manager import barbican_key_manager | |
29 | from castellan.key_manager import symmetric_key | |
30 | from castellan.tests.functional import config | |
31 | from castellan.tests.functional.key_manager import test_key_manager | |
32 | ||
33 | ||
34 | CONF = config.get_config() | |
35 | ||
36 | ||
37 | class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase): | |
38 | ||
39 | def _create_key_manager(self): | |
40 | return barbican_key_manager.BarbicanKeyManager() | |
41 | ||
42 | def setUp(self): | |
43 | super(BarbicanKeyManagerTestCase, self).setUp() | |
44 | username = CONF.identity.username | |
45 | password = CONF.identity.password | |
46 | project_name = CONF.identity.project_name | |
47 | auth_url = CONF.identity.uri | |
48 | keystone_client = client.Client(username=username, | |
49 | password=password, | |
50 | project_name=project_name, | |
51 | auth_url=auth_url) | |
52 | self.ctxt = context.RequestContext( | |
53 | auth_token=keystone_client.auth_token) | |
54 | ||
55 | def tearDown(self): | |
56 | super(BarbicanKeyManagerTestCase, self).tearDown() | |
57 | ||
58 | def test_create_key(self): | |
59 | key_uuid = self.key_mgr.create_key(self.ctxt, | |
60 | algorithm='AES', | |
61 | length=256) | |
62 | self.addCleanup(self.key_mgr.delete_key, self.ctxt, key_uuid) | |
63 | self.assertIsNotNone(key_uuid) | |
64 | ||
65 | def test_create_null_context(self): | |
66 | self.assertRaises(exception.Forbidden, | |
67 | self.key_mgr.create_key, None, 'AES', 256) | |
68 | ||
69 | def test_delete_symmetric_key(self): | |
70 | key_uuid = self.key_mgr.create_key(self.ctxt, | |
71 | algorithm='AES', | |
72 | length=256) | |
73 | self.key_mgr.delete_key(self.ctxt, key_uuid) | |
74 | try: | |
75 | self.key_mgr.get_key(self.ctxt, key_uuid) | |
76 | except barbican_exceptions.HTTPClientError as e: | |
77 | self.assertEqual(404, e.status_code) | |
78 | else: | |
79 | self.fail('No exception when deleting non-existent key') | |
80 | ||
81 | def test_delete_null_context(self): | |
82 | key_uuid = self.key_mgr.create_key(self.ctxt, | |
83 | algorithm='AES', | |
84 | length=256) | |
85 | self.addCleanup(self.key_mgr.delete_key, self.ctxt, key_uuid) | |
86 | self.assertRaises(exception.Forbidden, | |
87 | self.key_mgr.delete_key, None, key_uuid) | |
88 | ||
89 | def test_delete_null_key(self): | |
90 | self.assertRaises(exception.KeyManagerError, | |
91 | self.key_mgr.delete_key, self.ctxt, None) | |
92 | ||
93 | def test_delete_unknown_key(self): | |
94 | bad_key_uuid = str(uuid.uuid4()) | |
95 | self.assertRaises(barbican_exceptions.HTTPClientError, | |
96 | self.key_mgr.delete_key, self.ctxt, bad_key_uuid) | |
97 | ||
98 | def test_get_key(self): | |
99 | secret_key = b'\x01\x02\xA0\xB3' | |
100 | key = symmetric_key.SymmetricKey('AES', secret_key) | |
101 | ||
102 | uuid = self.key_mgr.store_key(self.ctxt, key) | |
103 | self.addCleanup(self.key_mgr.delete_key, self.ctxt, uuid) | |
104 | ||
105 | retrieved_key = self.key_mgr.get_key(self.ctxt, uuid) | |
106 | self.assertEqual(key.get_encoded(), retrieved_key.get_encoded()) | |
107 | ||
108 | def test_get_null_context(self): | |
109 | key_uuid = self.key_mgr.create_key(self.ctxt, | |
110 | algorithm='AES', | |
111 | length=256) | |
112 | self.assertRaises(exception.Forbidden, | |
113 | self.key_mgr.get_key, None, key_uuid) | |
114 | ||
115 | def test_get_null_key(self): | |
116 | key_uuid = self.key_mgr.create_key(self.ctxt, | |
117 | algorithm='AES', | |
118 | length=256) | |
119 | self.addCleanup(self.key_mgr.delete_key, self.ctxt, key_uuid) | |
120 | self.assertRaises(exception.KeyManagerError, | |
121 | self.key_mgr.get_key, self.ctxt, None) | |
122 | ||
123 | def test_get_unknown_key(self): | |
124 | key_uuid = self.key_mgr.create_key(self.ctxt, | |
125 | algorithm='AES', | |
126 | length=256) | |
127 | self.addCleanup(self.key_mgr.delete_key, self.ctxt, key_uuid) | |
128 | bad_key_uuid = str(uuid.uuid4()) | |
129 | self.assertRaises(barbican_exceptions.HTTPClientError, | |
130 | self.key_mgr.get_key, self.ctxt, bad_key_uuid) | |
131 | ||
132 | def test_store(self): | |
133 | secret_key = b'\x01\x02\xA0\xB3' | |
134 | key = symmetric_key.SymmetricKey('AES', secret_key) | |
135 | ||
136 | uuid = self.key_mgr.store_key(self.ctxt, key) | |
137 | self.addCleanup(self.key_mgr.delete_key, self.ctxt, uuid) | |
138 | ||
139 | retrieved_key = self.key_mgr.get_key(self.ctxt, uuid) | |
140 | self.assertEqual(key.get_encoded(), retrieved_key.get_encoded()) | |
141 | ||
142 | def test_store_null_context(self): | |
143 | secret_key = b'\x01\x02\xA0\xB3' | |
144 | key = symmetric_key.SymmetricKey('AES', secret_key) | |
145 | ||
146 | self.assertRaises(exception.Forbidden, | |
147 | self.key_mgr.store_key, None, key) |
0 | # Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Test cases for the key manager. | |
17 | """ | |
18 | ||
19 | from castellan.tests import base | |
20 | ||
21 | ||
22 | class KeyManagerTestCase(base.TestCase): | |
23 | ||
24 | def _create_key_manager(self): | |
25 | raise NotImplementedError() | |
26 | ||
27 | def setUp(self): | |
28 | super(KeyManagerTestCase, self).setUp() | |
29 | ||
30 | self.key_mgr = self._create_key_manager() |
0 | [DEFAULT] | |
1 | output_file = etc/castellan/castellan-functional.conf.sample | |
2 | wrap_width = 79 | |
3 | namespace = castellan.tests.functional.config |
22 | 22 | packages = |
23 | 23 | castellan |
24 | 24 | |
25 | [entry_points] | |
26 | oslo.config.opts = | |
27 | castellan.tests.functional.config = castellan.tests.functional.config:list_opts | |
28 | ||
25 | 29 | [build_sphinx] |
26 | 30 | source-dir = doc/source |
27 | 31 | build-dir = doc/build |
24 | 24 | [testenv:docs] |
25 | 25 | commands = python setup.py build_sphinx |
26 | 26 | |
27 | [testenv:functional] | |
28 | usedevelop = True | |
29 | install_command = pip install -U {opts} {packages} | |
30 | setenv = | |
31 | VIRTUAL_ENV={envdir} | |
32 | OS_TEST_PATH=./castellan/tests/functional | |
33 | deps = -r{toxinidir}/requirements.txt | |
34 | -r{toxinidir}/test-requirements.txt | |
35 | commands = python setup.py testr --slowest --testr-args='{posargs}' | |
36 | ||
37 | [testenv:genconfig] | |
38 | commands = | |
39 | oslo-config-generator --config-file=etc/castellan/functional-config-generator.conf | |
40 | #TODO(kfarr): add config generator for main Castellan options | |
41 | ||
27 | 42 | [flake8] |
28 | 43 | # H803 skipped on purpose per list discussion. |
29 | 44 | # E123, E125 skipped as they are invalid PEP-8. |