Package list python-castellan / a6c9df4
Move unit tests to unit test folder Change-Id: Ife49e3b046a841a6fd8ac698b9d19c66850eedfd Kaitlin Farr 6 years ago
19 changed file(s) with 650 addition(s) and 649 deletion(s). Raw diff Collapse all Expand all
11 test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
22 OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
33 OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
4 ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
4 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./castellan/tests} $LISTOPT $IDOPTION
55 test_id_option=--load-list $IDFILE
66 test_list_option=--list
+0
-0
castellan/tests/key_manager/__init__.py less more
(Empty file)
+0
-24
castellan/tests/key_manager/fake.py less more
0 # Copyright 2011 Justin Santa Barbara
1 # Copyright 2012 OpenStack Foundation
2 # All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15
16 """Implementation of a fake key manager."""
17
18
19 from castellan.tests.key_manager import mock_key_manager
20
21
22 def fake_api():
23 return mock_key_manager.MockKeyManager()
+0
-157
castellan/tests/key_manager/mock_key_manager.py less more
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 A mock implementation of a key manager that stores keys in a dictionary.
17
18 This key manager implementation is primarily intended for testing. In
19 particular, it does not store keys persistently. Lack of a centralized key
20 store also makes this implementation unsuitable for use among different
21 services.
22
23 Note: Instantiating this class multiple times will create separate key stores.
24 Keys created in one instance will not be accessible from other instances of
25 this class.
26 """
27
28 import array
29 import binascii
30 import random
31 import uuid
32
33 from castellan.common import exception
34 from castellan.key_manager import key_manager
35 from castellan.key_manager import symmetric_key as sym_key
36
37
38 class MockKeyManager(key_manager.KeyManager):
39
40 """Mocking manager for integration tests.
41
42 This mock key manager implementation supports all the methods specified
43 by the key manager interface. This implementation stores keys within a
44 dictionary, and as a result, it is not acceptable for use across different
45 services. Side effects (e.g., raising exceptions) for each method are
46 handled as specified by the key manager interface.
47
48 This key manager is not suitable for use in production deployments.
49 """
50
51 def __init__(self):
52 self.keys = {}
53
54 def _generate_hex_key(self, **kwargs):
55 key_length = kwargs.get('key_length', 256)
56 # hex digit => 4 bits
57 length = int(key_length / 4)
58 hex_encoded = self._generate_password(length=length,
59 symbolgroups='0123456789ABCDEF')
60 return hex_encoded
61
62 def _generate_key(self, **kwargs):
63 _hex = self._generate_hex_key(**kwargs)
64 return sym_key.SymmetricKey(
65 'AES',
66 array.array('B', binascii.unhexlify(_hex)).tolist())
67
68 def create_key(self, context, **kwargs):
69 """Creates a key.
70
71 This implementation returns a UUID for the created key. A
72 Forbidden exception is raised if the specified context is None.
73 """
74 if context is None:
75 raise exception.Forbidden()
76
77 key = self._generate_key(**kwargs)
78 return self.store_key(context, key)
79
80 def _generate_key_id(self):
81 key_id = str(uuid.uuid4())
82 while key_id in self.keys:
83 key_id = str(uuid.uuid4())
84
85 return key_id
86
87 def store_key(self, context, key, **kwargs):
88 """Stores (i.e., registers) a key with the key manager."""
89 if context is None:
90 raise exception.Forbidden()
91
92 key_id = self._generate_key_id()
93 self.keys[key_id] = key
94
95 return key_id
96
97 def copy_key(self, context, key_id, **kwargs):
98 if context is None:
99 raise exception.Forbidden()
100
101 copied_key_id = self._generate_key_id()
102 self.keys[copied_key_id] = self.keys[key_id]
103
104 return copied_key_id
105
106 def get_key(self, context, key_id, **kwargs):
107 """Retrieves the key identified by the specified id.
108
109 This implementation returns the key that is associated with the
110 specified UUID. A Forbidden exception is raised if the specified
111 context is None; a KeyError is raised if the UUID is invalid.
112 """
113 if context is None:
114 raise exception.Forbidden()
115
116 return self.keys[key_id]
117
118 def delete_key(self, context, key_id, **kwargs):
119 """Deletes the key identified by the specified id.
120
121 A Forbidden exception is raised if the context is None and a
122 KeyError is raised if the UUID is invalid.
123 """
124 if context is None:
125 raise exception.Forbidden()
126
127 del self.keys[key_id]
128
129 def _generate_password(self, length, symbolgroups):
130 """Generate a random password from the supplied symbol groups.
131
132 At least one symbol from each group will be included. Unpredictable
133 results if length is less than the number of symbol groups.
134
135 Believed to be reasonably secure (with a reasonable password length!)
136 """
137 # NOTE(jerdfelt): Some password policies require at least one character
138 # from each group of symbols, so start off with one random character
139 # from each symbol group
140 password = [random.choice(s) for s in symbolgroups]
141 # If length < len(symbolgroups), the leading characters will only
142 # be from the first length groups. Try our best to not be predictable
143 # by shuffling and then truncating.
144 random.shuffle(password)
145 password = password[:length]
146 length -= len(password)
147
148 # then fill with random characters from all symbol groups
149 symbols = ''.join(symbolgroups)
150 password.extend([random.choice(symbols) for _i in range(length)])
151
152 # finally shuffle to ensure first x characters aren't from a
153 # predictable group
154 random.shuffle(password)
155
156 return ''.join(password)
+0
-218
castellan/tests/key_manager/test_barbican_key_manager.py less more
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 """
16 Test cases for the barbican key manager.
17 """
18
19 import array
20
21 import mock
22
23 from castellan.common import exception
24 from castellan.key_manager import barbican_key_manager
25 from castellan.key_manager import symmetric_key as key_manager_key
26 from castellan.tests.key_manager import test_key_manager
27
28
29 class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase):
30
31 def _create_key_manager(self):
32 return barbican_key_manager.BarbicanKeyManager()
33
34 def setUp(self):
35 super(BarbicanKeyManagerTestCase, self).setUp()
36
37 # Create fake auth_token
38 self.ctxt = mock.Mock()
39 self.ctxt.auth_token = "fake_token"
40
41 # Create mock barbican client
42 self._build_mock_barbican()
43
44 # Create a key_id, secret_ref, pre_hex, and hex to use
45 self.key_id = "d152fa13-2b41-42ca-a934-6c21566c0f40"
46 self.secret_ref = ("http://host:9311/v1/secrets/" + self.key_id)
47 self.pre_hex = "AIDxQp2++uAbKaTVDMXFYIu8PIugJGqkK0JLqkU0rhY="
48 self.hex = ("0080f1429dbefae01b29a4d50cc5c5608bbc3c8ba0246aa42b424baa4"
49 "534ae16")
50 self.key_mgr._base_url = "http://host:9311/v1/"
51 self.addCleanup(self._restore)
52
53 def _restore(self):
54 try:
55 getattr(self, 'original_key')
56 key_manager_key.SymmetricKey = self.original_key
57 except AttributeError:
58 return None
59
60 def _build_mock_barbican(self):
61 self.mock_barbican = mock.MagicMock(name='mock_barbican')
62
63 # Set commonly used methods
64 self.get = self.mock_barbican.secrets.get
65 self.delete = self.mock_barbican.secrets.delete
66 self.store = self.mock_barbican.secrets.store
67 self.create = self.mock_barbican.secrets.create
68
69 self.key_mgr._barbican_client = self.mock_barbican
70 self.key_mgr._current_context = self.ctxt
71
72 def _build_mock_symKey(self):
73 self.mock_symKey = mock.Mock()
74
75 def fake_sym_key(alg, key):
76 self.mock_symKey.get_encoded.return_value = key
77 self.mock_symKey.get_algorithm.return_value = alg
78 return self.mock_symKey
79 self.original_key = key_manager_key.SymmetricKey
80 key_manager_key.SymmetricKey = fake_sym_key
81
82 def test_copy_key(self):
83 # Create metadata for original secret
84 original_secret_metadata = mock.Mock()
85 original_secret_metadata.algorithm = mock.sentinel.alg
86 original_secret_metadata.bit_length = mock.sentinel.bit
87 original_secret_metadata.name = mock.sentinel.name
88 original_secret_metadata.expiration = mock.sentinel.expiration
89 original_secret_metadata.mode = mock.sentinel.mode
90 content_types = {'default': 'fake_type'}
91 original_secret_metadata.content_types = content_types
92 original_secret_data = mock.Mock()
93 original_secret_metadata.payload = original_secret_data
94
95 # Create href for copied secret
96 copied_secret = mock.Mock()
97 copied_secret.store.return_value = (
98 'http://http://host:9311/v1/secrets/uuid')
99
100 # Set get and create return values
101 self.get.return_value = original_secret_metadata
102 self.create.return_value = copied_secret
103
104 # Create the mock key
105 self._build_mock_symKey()
106
107 # Copy the original
108 self.key_mgr.copy_key(self.ctxt, self.key_id)
109
110 # Assert proper methods were called
111 self.get.assert_called_once_with(self.secret_ref)
112 self.create.assert_called_once_with(
113 payload=self.mock_symKey.get_encoded(),
114 algorithm=mock.sentinel.alg,
115 expiration=mock.sentinel.expiration)
116 copied_secret.store.assert_called_once_with()
117
118 def test_copy_null_context(self):
119 self.key_mgr._barbican_client = None
120 self.assertRaises(exception.Forbidden,
121 self.key_mgr.copy_key, None, self.key_id)
122
123 def test_create_key(self):
124 # Create order_ref_url and assign return value
125 order_ref_url = ("http://localhost:9311/v1/orders/"
126 "4fe939b7-72bc-49aa-bd1e-e979589858af")
127 key_order = mock.Mock()
128 self.mock_barbican.orders.create_key.return_value = key_order
129 key_order.submit.return_value = order_ref_url
130
131 # Create order and assign return value
132 order = mock.Mock()
133 order.secret_ref = self.secret_ref
134 self.mock_barbican.orders.get.return_value = order
135
136 # Create the key, get the UUID
137 returned_uuid = self.key_mgr.create_key(self.ctxt,
138 algorithm='AES',
139 length=256)
140
141 self.mock_barbican.orders.get.assert_called_once_with(order_ref_url)
142 self.assertEqual(self.key_id, returned_uuid)
143
144 def test_create_null_context(self):
145 self.key_mgr._barbican_client = None
146 self.assertRaises(exception.Forbidden,
147 self.key_mgr.create_key, None, 'AES', 256)
148
149 def test_delete_null_context(self):
150 self.key_mgr._barbican_client = None
151 self.assertRaises(exception.Forbidden,
152 self.key_mgr.delete_key, None, self.key_id)
153
154 def test_delete_key(self):
155 self.key_mgr.delete_key(self.ctxt, self.key_id)
156 self.delete.assert_called_once_with(self.secret_ref)
157
158 def test_delete_unknown_key(self):
159 self.assertRaises(exception.KeyManagerError,
160 self.key_mgr.delete_key, self.ctxt, None)
161
162 def test_get_key(self):
163 original_secret_metadata = mock.Mock()
164 original_secret_metadata.algorithm = mock.sentinel.alg
165 original_secret_metadata.bit_length = mock.sentinel.bit
166 original_secret_data = mock.Mock()
167 original_secret_metadata.payload = original_secret_data
168
169 self.mock_barbican.secrets.get.return_value = original_secret_metadata
170 key = self.key_mgr.get_key(self.ctxt, self.key_id)
171
172 self.get.assert_called_once_with(self.secret_ref)
173 self.assertEqual(key.get_encoded(), original_secret_data)
174
175 def test_get_null_context(self):
176 self.key_mgr._barbican_client = None
177 self.assertRaises(exception.Forbidden,
178 self.key_mgr.get_key, None, self.key_id)
179
180 def test_get_unknown_key(self):
181 self.assertRaises(exception.KeyManagerError,
182 self.key_mgr.get_key, self.ctxt, None)
183
184 def test_store_key_base64(self):
185 # Create Key to store
186 secret_key = array.array('B', [0x01, 0x02, 0xA0, 0xB3]).tolist()
187 _key = key_manager_key.SymmetricKey('AES', secret_key)
188
189 # Define the return values
190 secret = mock.Mock()
191 self.create.return_value = secret
192 secret.store.return_value = self.secret_ref
193
194 # Store the Key
195 returned_uuid = self.key_mgr.store_key(self.ctxt, _key)
196
197 self.create.assert_called_once_with(algorithm='AES',
198 payload=secret_key,
199 expiration=None)
200 self.assertEqual(self.key_id, returned_uuid)
201
202 def test_store_key_plaintext(self):
203 # Create the plaintext key
204 secret_key_text = "This is a test text key."
205 _key = key_manager_key.SymmetricKey('AES', secret_key_text)
206
207 # Store the Key
208 self.key_mgr.store_key(self.ctxt, _key)
209 self.create.assert_called_once_with(algorithm='AES',
210 payload=secret_key_text,
211 expiration=None)
212 self.assertEqual(0, self.store.call_count)
213
214 def test_store_null_context(self):
215 self.key_mgr._barbican_client = None
216 self.assertRaises(exception.Forbidden,
217 self.key_mgr.store_key, None, None)
+0
-68
castellan/tests/key_manager/test_key.py less more
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 classes.
17 """
18
19 import array
20 import binascii
21
22 from castellan.key_manager import symmetric_key as sym_key
23 from castellan.tests import base
24
25
26 class KeyTestCase(base.TestCase):
27
28 def _create_key(self):
29 raise NotImplementedError()
30
31 def setUp(self):
32 super(KeyTestCase, self).setUp()
33
34 self.key = self._create_key()
35
36
37 class SymmetricKeyTestCase(KeyTestCase):
38
39 def _create_key(self):
40 return sym_key.SymmetricKey(self.algorithm, self.encoded)
41
42 def setUp(self):
43 self.algorithm = 'AES'
44 self.encoded = array.array('B', binascii.unhexlify('0' * 64)).tolist()
45
46 super(SymmetricKeyTestCase, self).setUp()
47
48 def test_get_algorithm(self):
49 self.assertEqual(self.key.get_algorithm(), self.algorithm)
50
51 def test_get_format(self):
52 self.assertEqual(self.key.get_format(), 'RAW')
53
54 def test_get_encoded(self):
55 self.assertEqual(self.key.get_encoded(), self.encoded)
56
57 def test___eq__(self):
58 self.assertTrue(self.key == self.key)
59
60 self.assertFalse(self.key is None)
61 self.assertFalse(None == self.key)
62
63 def test___ne__(self):
64 self.assertFalse(self.key != self.key)
65
66 self.assertTrue(self.key is not None)
67 self.assertTrue(None != self.key)
+0
-31
castellan/tests/key_manager/test_key_manager.py less more
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
-103
castellan/tests/key_manager/test_mock_key_manager.py less more
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 mock key manager.
17 """
18
19 import array
20 import binascii
21
22 from oslo_context import context
23
24 from castellan.common import exception
25 from castellan.key_manager import symmetric_key as sym_key
26 from castellan.tests.key_manager import mock_key_manager as mock_key_mgr
27 from castellan.tests.key_manager import test_key_manager as test_key_mgr
28
29
30 class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
31
32 def _create_key_manager(self):
33 return mock_key_mgr.MockKeyManager()
34
35 def setUp(self):
36 super(MockKeyManagerTestCase, self).setUp()
37
38 self.context = context.RequestContext('fake', 'fake')
39
40 def test_create_key(self):
41 key_id_1 = self.key_mgr.create_key(self.context)
42 key_id_2 = self.key_mgr.create_key(self.context)
43 # ensure that the UUIDs are unique
44 self.assertNotEqual(key_id_1, key_id_2)
45
46 def test_create_key_with_length(self):
47 for length in [64, 128, 256]:
48 key_id = self.key_mgr.create_key(self.context, key_length=length)
49 key = self.key_mgr.get_key(self.context, key_id)
50 self.assertEqual(length / 8, len(key.get_encoded()))
51
52 def test_create_null_context(self):
53 self.assertRaises(exception.Forbidden,
54 self.key_mgr.create_key, None)
55
56 def test_store_and_get_key(self):
57 secret_key = array.array('B', binascii.unhexlify('0' * 64)).tolist()
58 _key = sym_key.SymmetricKey('AES', secret_key)
59 key_id = self.key_mgr.store_key(self.context, _key)
60
61 actual_key = self.key_mgr.get_key(self.context, key_id)
62 self.assertEqual(_key, actual_key)
63
64 def test_store_null_context(self):
65 self.assertRaises(exception.Forbidden,
66 self.key_mgr.store_key, None, None)
67
68 def test_copy_key(self):
69 key_id = self.key_mgr.create_key(self.context)
70 key = self.key_mgr.get_key(self.context, key_id)
71
72 copied_key_id = self.key_mgr.copy_key(self.context, key_id)
73 copied_key = self.key_mgr.get_key(self.context, copied_key_id)
74
75 self.assertNotEqual(key_id, copied_key_id)
76 self.assertEqual(key, copied_key)
77
78 def test_copy_null_context(self):
79 self.assertRaises(exception.Forbidden,
80 self.key_mgr.copy_key, None, None)
81
82 def test_get_null_context(self):
83 self.assertRaises(exception.Forbidden,
84 self.key_mgr.get_key, None, None)
85
86 def test_get_unknown_key(self):
87 self.assertRaises(KeyError, self.key_mgr.get_key, self.context, None)
88
89 def test_delete_key(self):
90 key_id = self.key_mgr.create_key(self.context)
91 self.key_mgr.delete_key(self.context, key_id)
92
93 self.assertRaises(KeyError, self.key_mgr.get_key, self.context,
94 key_id)
95
96 def test_delete_null_context(self):
97 self.assertRaises(exception.Forbidden,
98 self.key_mgr.delete_key, None, None)
99
100 def test_delete_unknown_key(self):
101 self.assertRaises(KeyError, self.key_mgr.delete_key, self.context,
102 None)
+0
-47
castellan/tests/key_manager/test_not_implemented_key_manager.py less more
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 not implemented key manager.
17 """
18
19 from castellan.key_manager import not_implemented_key_manager
20 from castellan.tests.key_manager import test_key_manager
21
22
23 class NotImplementedKeyManagerTestCase(test_key_manager.KeyManagerTestCase):
24
25 def _create_key_manager(self):
26 return not_implemented_key_manager.NotImplementedKeyManager()
27
28 def test_create_key(self):
29 self.assertRaises(NotImplementedError,
30 self.key_mgr.create_key, None)
31
32 def test_store_key(self):
33 self.assertRaises(NotImplementedError,
34 self.key_mgr.store_key, None, None)
35
36 def test_copy_key(self):
37 self.assertRaises(NotImplementedError,
38 self.key_mgr.copy_key, None, None)
39
40 def test_get_key(self):
41 self.assertRaises(NotImplementedError,
42 self.key_mgr.get_key, None, None)
43
44 def test_delete_key(self):
45 self.assertRaises(NotImplementedError,
46 self.key_mgr.delete_key, None, None)
0 # Copyright 2011 Justin Santa Barbara
1 # Copyright 2012 OpenStack Foundation
2 # All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15
16 """Implementation of a fake key manager."""
17
18
19 from castellan.tests.unit.key_manager import mock_key_manager
20
21
22 def fake_api():
23 return mock_key_manager.MockKeyManager()
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 A mock implementation of a key manager that stores keys in a dictionary.
17
18 This key manager implementation is primarily intended for testing. In
19 particular, it does not store keys persistently. Lack of a centralized key
20 store also makes this implementation unsuitable for use among different
21 services.
22
23 Note: Instantiating this class multiple times will create separate key stores.
24 Keys created in one instance will not be accessible from other instances of
25 this class.
26 """
27
28 import array
29 import binascii
30 import random
31 import uuid
32
33 from castellan.common import exception
34 from castellan.key_manager import key_manager
35 from castellan.key_manager import symmetric_key as sym_key
36
37
38 class MockKeyManager(key_manager.KeyManager):
39
40 """Mocking manager for integration tests.
41
42 This mock key manager implementation supports all the methods specified
43 by the key manager interface. This implementation stores keys within a
44 dictionary, and as a result, it is not acceptable for use across different
45 services. Side effects (e.g., raising exceptions) for each method are
46 handled as specified by the key manager interface.
47
48 This key manager is not suitable for use in production deployments.
49 """
50
51 def __init__(self):
52 self.keys = {}
53
54 def _generate_hex_key(self, **kwargs):
55 key_length = kwargs.get('key_length', 256)
56 # hex digit => 4 bits
57 length = int(key_length / 4)
58 hex_encoded = self._generate_password(length=length,
59 symbolgroups='0123456789ABCDEF')
60 return hex_encoded
61
62 def _generate_key(self, **kwargs):
63 _hex = self._generate_hex_key(**kwargs)
64 return sym_key.SymmetricKey(
65 'AES',
66 array.array('B', binascii.unhexlify(_hex)).tolist())
67
68 def create_key(self, context, **kwargs):
69 """Creates a key.
70
71 This implementation returns a UUID for the created key. A
72 Forbidden exception is raised if the specified context is None.
73 """
74 if context is None:
75 raise exception.Forbidden()
76
77 key = self._generate_key(**kwargs)
78 return self.store_key(context, key)
79
80 def _generate_key_id(self):
81 key_id = str(uuid.uuid4())
82 while key_id in self.keys:
83 key_id = str(uuid.uuid4())
84
85 return key_id
86
87 def store_key(self, context, key, **kwargs):
88 """Stores (i.e., registers) a key with the key manager."""
89 if context is None:
90 raise exception.Forbidden()
91
92 key_id = self._generate_key_id()
93 self.keys[key_id] = key
94
95 return key_id
96
97 def copy_key(self, context, key_id, **kwargs):
98 if context is None:
99 raise exception.Forbidden()
100
101 copied_key_id = self._generate_key_id()
102 self.keys[copied_key_id] = self.keys[key_id]
103
104 return copied_key_id
105
106 def get_key(self, context, key_id, **kwargs):
107 """Retrieves the key identified by the specified id.
108
109 This implementation returns the key that is associated with the
110 specified UUID. A Forbidden exception is raised if the specified
111 context is None; a KeyError is raised if the UUID is invalid.
112 """
113 if context is None:
114 raise exception.Forbidden()
115
116 return self.keys[key_id]
117
118 def delete_key(self, context, key_id, **kwargs):
119 """Deletes the key identified by the specified id.
120
121 A Forbidden exception is raised if the context is None and a
122 KeyError is raised if the UUID is invalid.
123 """
124 if context is None:
125 raise exception.Forbidden()
126
127 del self.keys[key_id]
128
129 def _generate_password(self, length, symbolgroups):
130 """Generate a random password from the supplied symbol groups.
131
132 At least one symbol from each group will be included. Unpredictable
133 results if length is less than the number of symbol groups.
134
135 Believed to be reasonably secure (with a reasonable password length!)
136 """
137 # NOTE(jerdfelt): Some password policies require at least one character
138 # from each group of symbols, so start off with one random character
139 # from each symbol group
140 password = [random.choice(s) for s in symbolgroups]
141 # If length < len(symbolgroups), the leading characters will only
142 # be from the first length groups. Try our best to not be predictable
143 # by shuffling and then truncating.
144 random.shuffle(password)
145 password = password[:length]
146 length -= len(password)
147
148 # then fill with random characters from all symbol groups
149 symbols = ''.join(symbolgroups)
150 password.extend([random.choice(symbols) for _i in range(length)])
151
152 # finally shuffle to ensure first x characters aren't from a
153 # predictable group
154 random.shuffle(password)
155
156 return ''.join(password)
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 """
16 Test cases for the barbican key manager.
17 """
18
19 import array
20
21 import mock
22
23 from castellan.common import exception
24 from castellan.key_manager import barbican_key_manager
25 from castellan.key_manager import symmetric_key as key_manager_key
26 from castellan.tests.unit.key_manager import test_key_manager
27
28
29 class BarbicanKeyManagerTestCase(test_key_manager.KeyManagerTestCase):
30
31 def _create_key_manager(self):
32 return barbican_key_manager.BarbicanKeyManager()
33
34 def setUp(self):
35 super(BarbicanKeyManagerTestCase, self).setUp()
36
37 # Create fake auth_token
38 self.ctxt = mock.Mock()
39 self.ctxt.auth_token = "fake_token"
40
41 # Create mock barbican client
42 self._build_mock_barbican()
43
44 # Create a key_id, secret_ref, pre_hex, and hex to use
45 self.key_id = "d152fa13-2b41-42ca-a934-6c21566c0f40"
46 self.secret_ref = ("http://host:9311/v1/secrets/" + self.key_id)
47 self.pre_hex = "AIDxQp2++uAbKaTVDMXFYIu8PIugJGqkK0JLqkU0rhY="
48 self.hex = ("0080f1429dbefae01b29a4d50cc5c5608bbc3c8ba0246aa42b424baa4"
49 "534ae16")
50 self.key_mgr._base_url = "http://host:9311/v1/"
51 self.addCleanup(self._restore)
52
53 def _restore(self):
54 try:
55 getattr(self, 'original_key')
56 key_manager_key.SymmetricKey = self.original_key
57 except AttributeError:
58 return None
59
60 def _build_mock_barbican(self):
61 self.mock_barbican = mock.MagicMock(name='mock_barbican')
62
63 # Set commonly used methods
64 self.get = self.mock_barbican.secrets.get
65 self.delete = self.mock_barbican.secrets.delete
66 self.store = self.mock_barbican.secrets.store
67 self.create = self.mock_barbican.secrets.create
68
69 self.key_mgr._barbican_client = self.mock_barbican
70 self.key_mgr._current_context = self.ctxt
71
72 def _build_mock_symKey(self):
73 self.mock_symKey = mock.Mock()
74
75 def fake_sym_key(alg, key):
76 self.mock_symKey.get_encoded.return_value = key
77 self.mock_symKey.get_algorithm.return_value = alg
78 return self.mock_symKey
79 self.original_key = key_manager_key.SymmetricKey
80 key_manager_key.SymmetricKey = fake_sym_key
81
82 def test_copy_key(self):
83 # Create metadata for original secret
84 original_secret_metadata = mock.Mock()
85 original_secret_metadata.algorithm = mock.sentinel.alg
86 original_secret_metadata.bit_length = mock.sentinel.bit
87 original_secret_metadata.name = mock.sentinel.name
88 original_secret_metadata.expiration = mock.sentinel.expiration
89 original_secret_metadata.mode = mock.sentinel.mode
90 content_types = {'default': 'fake_type'}
91 original_secret_metadata.content_types = content_types
92 original_secret_data = mock.Mock()
93 original_secret_metadata.payload = original_secret_data
94
95 # Create href for copied secret
96 copied_secret = mock.Mock()
97 copied_secret.store.return_value = (
98 'http://http://host:9311/v1/secrets/uuid')
99
100 # Set get and create return values
101 self.get.return_value = original_secret_metadata
102 self.create.return_value = copied_secret
103
104 # Create the mock key
105 self._build_mock_symKey()
106
107 # Copy the original
108 self.key_mgr.copy_key(self.ctxt, self.key_id)
109
110 # Assert proper methods were called
111 self.get.assert_called_once_with(self.secret_ref)
112 self.create.assert_called_once_with(
113 payload=self.mock_symKey.get_encoded(),
114 algorithm=mock.sentinel.alg,
115 expiration=mock.sentinel.expiration)
116 copied_secret.store.assert_called_once_with()
117
118 def test_copy_null_context(self):
119 self.key_mgr._barbican_client = None
120 self.assertRaises(exception.Forbidden,
121 self.key_mgr.copy_key, None, self.key_id)
122
123 def test_create_key(self):
124 # Create order_ref_url and assign return value
125 order_ref_url = ("http://localhost:9311/v1/orders/"
126 "4fe939b7-72bc-49aa-bd1e-e979589858af")
127 key_order = mock.Mock()
128 self.mock_barbican.orders.create_key.return_value = key_order
129 key_order.submit.return_value = order_ref_url
130
131 # Create order and assign return value
132 order = mock.Mock()
133 order.secret_ref = self.secret_ref
134 self.mock_barbican.orders.get.return_value = order
135
136 # Create the key, get the UUID
137 returned_uuid = self.key_mgr.create_key(self.ctxt,
138 algorithm='AES',
139 length=256)
140
141 self.mock_barbican.orders.get.assert_called_once_with(order_ref_url)
142 self.assertEqual(self.key_id, returned_uuid)
143
144 def test_create_null_context(self):
145 self.key_mgr._barbican_client = None
146 self.assertRaises(exception.Forbidden,
147 self.key_mgr.create_key, None, 'AES', 256)
148
149 def test_delete_null_context(self):
150 self.key_mgr._barbican_client = None
151 self.assertRaises(exception.Forbidden,
152 self.key_mgr.delete_key, None, self.key_id)
153
154 def test_delete_key(self):
155 self.key_mgr.delete_key(self.ctxt, self.key_id)
156 self.delete.assert_called_once_with(self.secret_ref)
157
158 def test_delete_unknown_key(self):
159 self.assertRaises(exception.KeyManagerError,
160 self.key_mgr.delete_key, self.ctxt, None)
161
162 def test_get_key(self):
163 original_secret_metadata = mock.Mock()
164 original_secret_metadata.algorithm = mock.sentinel.alg
165 original_secret_metadata.bit_length = mock.sentinel.bit
166 original_secret_data = mock.Mock()
167 original_secret_metadata.payload = original_secret_data
168
169 self.mock_barbican.secrets.get.return_value = original_secret_metadata
170 key = self.key_mgr.get_key(self.ctxt, self.key_id)
171
172 self.get.assert_called_once_with(self.secret_ref)
173 self.assertEqual(key.get_encoded(), original_secret_data)
174
175 def test_get_null_context(self):
176 self.key_mgr._barbican_client = None
177 self.assertRaises(exception.Forbidden,
178 self.key_mgr.get_key, None, self.key_id)
179
180 def test_get_unknown_key(self):
181 self.assertRaises(exception.KeyManagerError,
182 self.key_mgr.get_key, self.ctxt, None)
183
184 def test_store_key_base64(self):
185 # Create Key to store
186 secret_key = array.array('B', [0x01, 0x02, 0xA0, 0xB3]).tolist()
187 _key = key_manager_key.SymmetricKey('AES', secret_key)
188
189 # Define the return values
190 secret = mock.Mock()
191 self.create.return_value = secret
192 secret.store.return_value = self.secret_ref
193
194 # Store the Key
195 returned_uuid = self.key_mgr.store_key(self.ctxt, _key)
196
197 self.create.assert_called_once_with(algorithm='AES',
198 payload=secret_key,
199 expiration=None)
200 self.assertEqual(self.key_id, returned_uuid)
201
202 def test_store_key_plaintext(self):
203 # Create the plaintext key
204 secret_key_text = "This is a test text key."
205 _key = key_manager_key.SymmetricKey('AES', secret_key_text)
206
207 # Store the Key
208 self.key_mgr.store_key(self.ctxt, _key)
209 self.create.assert_called_once_with(algorithm='AES',
210 payload=secret_key_text,
211 expiration=None)
212 self.assertEqual(0, self.store.call_count)
213
214 def test_store_null_context(self):
215 self.key_mgr._barbican_client = None
216 self.assertRaises(exception.Forbidden,
217 self.key_mgr.store_key, None, None)
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 classes.
17 """
18
19 import array
20 import binascii
21
22 from castellan.key_manager import symmetric_key as sym_key
23 from castellan.tests import base
24
25
26 class KeyTestCase(base.TestCase):
27
28 def _create_key(self):
29 raise NotImplementedError()
30
31 def setUp(self):
32 super(KeyTestCase, self).setUp()
33
34 self.key = self._create_key()
35
36
37 class SymmetricKeyTestCase(KeyTestCase):
38
39 def _create_key(self):
40 return sym_key.SymmetricKey(self.algorithm, self.encoded)
41
42 def setUp(self):
43 self.algorithm = 'AES'
44 self.encoded = array.array('B', binascii.unhexlify('0' * 64)).tolist()
45
46 super(SymmetricKeyTestCase, self).setUp()
47
48 def test_get_algorithm(self):
49 self.assertEqual(self.key.get_algorithm(), self.algorithm)
50
51 def test_get_format(self):
52 self.assertEqual(self.key.get_format(), 'RAW')
53
54 def test_get_encoded(self):
55 self.assertEqual(self.key.get_encoded(), self.encoded)
56
57 def test___eq__(self):
58 self.assertTrue(self.key == self.key)
59
60 self.assertFalse(self.key is None)
61 self.assertFalse(None == self.key)
62
63 def test___ne__(self):
64 self.assertFalse(self.key != self.key)
65
66 self.assertTrue(self.key is not None)
67 self.assertTrue(None != self.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 # 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 mock key manager.
17 """
18
19 import array
20 import binascii
21
22 from oslo_context import context
23
24 from castellan.common import exception
25 from castellan.key_manager import symmetric_key as sym_key
26 from castellan.tests.unit.key_manager import mock_key_manager as mock_key_mgr
27 from castellan.tests.unit.key_manager import test_key_manager as test_key_mgr
28
29
30 class MockKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
31
32 def _create_key_manager(self):
33 return mock_key_mgr.MockKeyManager()
34
35 def setUp(self):
36 super(MockKeyManagerTestCase, self).setUp()
37
38 self.context = context.RequestContext('fake', 'fake')
39
40 def test_create_key(self):
41 key_id_1 = self.key_mgr.create_key(self.context)
42 key_id_2 = self.key_mgr.create_key(self.context)
43 # ensure that the UUIDs are unique
44 self.assertNotEqual(key_id_1, key_id_2)
45
46 def test_create_key_with_length(self):
47 for length in [64, 128, 256]:
48 key_id = self.key_mgr.create_key(self.context, key_length=length)
49 key = self.key_mgr.get_key(self.context, key_id)
50 self.assertEqual(length / 8, len(key.get_encoded()))
51
52 def test_create_null_context(self):
53 self.assertRaises(exception.Forbidden,
54 self.key_mgr.create_key, None)
55
56 def test_store_and_get_key(self):
57 secret_key = array.array('B', binascii.unhexlify('0' * 64)).tolist()
58 _key = sym_key.SymmetricKey('AES', secret_key)
59 key_id = self.key_mgr.store_key(self.context, _key)
60
61 actual_key = self.key_mgr.get_key(self.context, key_id)
62 self.assertEqual(_key, actual_key)
63
64 def test_store_null_context(self):
65 self.assertRaises(exception.Forbidden,
66 self.key_mgr.store_key, None, None)
67
68 def test_copy_key(self):
69 key_id = self.key_mgr.create_key(self.context)
70 key = self.key_mgr.get_key(self.context, key_id)
71
72 copied_key_id = self.key_mgr.copy_key(self.context, key_id)
73 copied_key = self.key_mgr.get_key(self.context, copied_key_id)
74
75 self.assertNotEqual(key_id, copied_key_id)
76 self.assertEqual(key, copied_key)
77
78 def test_copy_null_context(self):
79 self.assertRaises(exception.Forbidden,
80 self.key_mgr.copy_key, None, None)
81
82 def test_get_null_context(self):
83 self.assertRaises(exception.Forbidden,
84 self.key_mgr.get_key, None, None)
85
86 def test_get_unknown_key(self):
87 self.assertRaises(KeyError, self.key_mgr.get_key, self.context, None)
88
89 def test_delete_key(self):
90 key_id = self.key_mgr.create_key(self.context)
91 self.key_mgr.delete_key(self.context, key_id)
92
93 self.assertRaises(KeyError, self.key_mgr.get_key, self.context,
94 key_id)
95
96 def test_delete_null_context(self):
97 self.assertRaises(exception.Forbidden,
98 self.key_mgr.delete_key, None, None)
99
100 def test_delete_unknown_key(self):
101 self.assertRaises(KeyError, self.key_mgr.delete_key, self.context,
102 None)
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 not implemented key manager.
17 """
18
19 from castellan.key_manager import not_implemented_key_manager
20 from castellan.tests.unit.key_manager import test_key_manager
21
22
23 class NotImplementedKeyManagerTestCase(test_key_manager.KeyManagerTestCase):
24
25 def _create_key_manager(self):
26 return not_implemented_key_manager.NotImplementedKeyManager()
27
28 def test_create_key(self):
29 self.assertRaises(NotImplementedError,
30 self.key_mgr.create_key, None)
31
32 def test_store_key(self):
33 self.assertRaises(NotImplementedError,
34 self.key_mgr.store_key, None, None)
35
36 def test_copy_key(self):
37 self.assertRaises(NotImplementedError,
38 self.key_mgr.copy_key, None, None)
39
40 def test_get_key(self):
41 self.assertRaises(NotImplementedError,
42 self.key_mgr.get_key, None, None)
43
44 def test_delete_key(self):
45 self.assertRaises(NotImplementedError,
46 self.key_mgr.delete_key, None, None)
77 install_command = pip install -U {opts} {packages}
88 setenv =
99 VIRTUAL_ENV={envdir}
10 OS_TEST_PATH=./castellan/tests/unit
1011 deps = -r{toxinidir}/requirements.txt
1112 -r{toxinidir}/test-requirements.txt
1213 commands = python setup.py testr --slowest --testr-args='{posargs}'