swift/test/unit/common/middleware/crypto/test_kms_keymaster.py
Thomas Goirand 85d3658d62 Fix kms_keymaster under Python 3
Depending on how the key was stored in Barbican, it may come out of
Castellan as a native string, which would not be suitable on Python 3.
Now, check that the secret is a byte string, and if it isn't, encode as
UTF-8 (to match Barbican's internal encoding).

Change-Id: I6da047716c05e4f2a9e1e74ca19afb62e812d172
Closes-Bug: #1847755
2019-10-13 21:58:50 -07:00

870 lines
36 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (c) 2015 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
import mock
import unittest
import sys
sys.modules['castellan'] = mock.Mock()
sys.modules['castellan.common'] = mock.Mock()
sys.modules['castellan.common.credentials'] = mock.Mock()
from keystoneauth1.exceptions.connection import ConnectFailure
from keystoneauth1.exceptions.http import Unauthorized
from keystoneclient.exceptions import DiscoveryFailure
from swift.common.middleware.crypto import kms_keymaster
from swift.common.swob import Request
from test.unit.common.middleware.helpers import FakeSwift, FakeAppThatExcepts
TEST_KMS_INVALID_KEY_ID = 'invalid-kms-key-id'
TEST_KMS_NONEXISTENT_KEY_ID = '11111111-1111-1111-1111-ffffffffffff'
TEST_KMS_OPAQUE_KEY_ID = '22222222-2222-2222-2222-aaaaaaaaaaaa'
TEST_KMS_SHORT_KEY_ID = '22222222-2222-2222-2222-bbbbbbbbbbbb'
TEST_KMS_DES_KEY_ID = '22222222-2222-2222-2222-cccccccccccc'
TEST_KMS_NONE_KEY_ID = '22222222-2222-2222-2222-dddddddddddd'
TEST_KMS_INVALID_API_VERSION = 'vBadVersion'
TEST_KMS_INVALID_USER_DOMAIN_NAME = "baduserdomainname"
TEST_KMS_CONNECT_FAILURE_URL = 'http://endpoint_url_connect_error:45621'
TEST_KMS_NON_BARBICAN_URL = 'http://endpoint_url_nonbarbican:45621'
TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF = {
'keymaster_config_path': 'PATH_TO_KEYMASTER_CONFIG_FILE',
}
TEST_KMS_KEYMASTER_CONF = {
'auth_endpoint': 'kmsauthurlv3',
'password': 'kmspass',
'username': 'kmsuser',
'user_domain_id': None,
'user_domain_name': 'default',
'project_id': None,
'project_name': 'kmsproject',
'project_domain_id': None,
'project_domain_name': 'default',
'key_id': 'valid_kms_key_id-abcdefg-123456'
}
def capture_start_response():
calls = []
def start_response(*args):
calls.append(args)
return start_response, calls
def mock_castellan_api_side_effect(*args, **kwargs):
return MockBarbicanKeyManager(args[0])
def mock_options_set_defaults_side_effect(*args, **kwargs):
'''
Add options from kwargs into args dict.
'''
args[0].update(kwargs)
def mock_config_opts_side_effect(*args, **kwargs):
return dict()
def mock_keystone_password_side_effect(auth_url, username, password,
project_name, user_domain_name,
project_domain_name, user_id,
user_domain_id, trust_id,
domain_id, domain_name, project_id,
project_domain_id, reauthenticate):
return MockPassword(auth_url, username, password, project_name,
user_domain_name, project_domain_name, user_id,
user_domain_id, trust_id, domain_id, domain_name,
project_id, project_domain_id, reauthenticate)
ERR_MESSAGE_SECRET_INCORRECTLY_SPECIFIED = 'Secret incorrectly specified.'
ERR_MESSAGE_KEY_UUID_NOT_FOUND = 'Key not found, uuid: '
class MockBarbicanKeyManager(object):
def __init__(self, conf):
self.conf = conf
def get(self, ctxt, key_id):
# If authentication fails, raise an exception here.
if (TEST_KMS_KEYMASTER_CONF['username'] !=
ctxt.username
or TEST_KMS_KEYMASTER_CONF['password'] !=
ctxt.password or
TEST_KMS_KEYMASTER_CONF['user_domain_name'] !=
ctxt.user_domain_name):
raise Unauthorized(
message='The request you have made requires authentication.',
http_status=401)
elif self.conf['auth_endpoint'] == TEST_KMS_CONNECT_FAILURE_URL:
raise ConnectFailure('Unable to establish connection')
elif self.conf['auth_endpoint'] == TEST_KMS_NON_BARBICAN_URL:
raise DiscoveryFailure(
'Could not determine a suitable URL for the plugin')
elif (self.conf['auth_endpoint'] !=
TEST_KMS_KEYMASTER_CONF['auth_endpoint']):
raise Unauthorized(
message='Cannot authorize API client.')
elif (key_id == TEST_KMS_NONEXISTENT_KEY_ID):
message = ERR_MESSAGE_KEY_UUID_NOT_FOUND + key_id
'''
Raising a ManagedObjectNotFoundError would require importing it
from castellan.common.exception. To avoid this import, raising a
general Exception.
'''
raise Exception(message)
elif key_id == TEST_KMS_INVALID_KEY_ID:
raise ValueError(ERR_MESSAGE_SECRET_INCORRECTLY_SPECIFIED)
elif key_id == TEST_KMS_NONE_KEY_ID:
return None
if 'unicode' in key_id:
key_str = key_id[0] * 32
else:
key_str = (str(key_id[0]) * 32).encode('utf8')
return MockBarbicanKey(key_str, key_id)
class MockBarbicanKey(object):
def __init__(self, key_material, key_id):
self.key_material = key_material
self.bit_length = len(key_material) * 8
if key_id == TEST_KMS_OPAQUE_KEY_ID:
self.format = 'Opaque'
else:
self.format = 'RAW'
self.algorithm = "aes"
if key_id == TEST_KMS_DES_KEY_ID:
self.format = 'des'
if key_id == TEST_KMS_SHORT_KEY_ID:
self.bit_length = 128
self.key_material[:128]
def get_encoded(self):
return self.key_material
def format(self):
return self.format
class MockPassword(object):
def __init__(self, auth_url, username, password, project_name,
user_domain_name, project_domain_name, user_id,
user_domain_id, trust_id, domain_id, domain_name, project_id,
project_domain_id, reauthenticate):
self.auth_url = auth_url
self.password = password
self.username = username
self.user_domain_name = user_domain_name
self.project_name = project_name
self.project_domain_name = project_domain_name
self.user_id = user_id,
self.user_domain_id = user_domain_id,
self.trust_id = trust_id,
self.domain_id = domain_id,
self.domain_name = domain_name,
self.project_id = project_id,
self.project_domain_id = project_domain_id,
self.reauthenticate = reauthenticate
class TestKmsKeymaster(unittest.TestCase):
"""
Unit tests for storing the encryption root secret in a Barbican external
key management system accessed using Castellan.
"""
def setUp(self):
super(TestKmsKeymaster, self).setUp()
self.swift = FakeSwift()
"""
Tests using the v3 Identity API, where all calls to Barbican are mocked.
"""
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch.object(kms_keymaster.KmsKeyMaster,
'_get_root_secret')
def test_filter_v3(self, mock_get_root_secret_from_kms,
mock_readconf):
mock_get_root_secret_from_kms.return_value = (
base64.b64encode(b'x' * 32))
mock_readconf.return_value = TEST_KMS_KEYMASTER_CONF
factory = kms_keymaster.filter_factory(TEST_KMS_KEYMASTER_CONF)
self.assertTrue(callable(factory))
self.assertTrue(callable(factory(self.swift)))
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch.object(kms_keymaster.KmsKeyMaster,
'_get_root_secret')
def test_app_exception_v3(self, mock_get_root_secret_from_kms,
mock_readconf):
mock_get_root_secret_from_kms.return_value = (
base64.b64encode(b'x' * 32))
mock_readconf.return_value = TEST_KMS_KEYMASTER_CONF
app = kms_keymaster.KmsKeyMaster(
FakeAppThatExcepts(), TEST_KMS_KEYMASTER_CONF)
req = Request.blank('/', environ={'REQUEST_METHOD': 'PUT'})
start_response, _ = capture_start_response()
self.assertRaises(Exception, app, req.environ, start_response)
@mock.patch.object(kms_keymaster.KmsKeyMaster, '_get_root_secret')
def test_get_root_secret(
self, mock_get_root_secret_from_kms):
# Successful call with coarse _get_root_secret_from_kms() mock.
mock_get_root_secret_from_kms.return_value = (
base64.b64encode(b'x' * 32))
# Provide valid Barbican configuration parameters in proxy-server
# config.
self.app = kms_keymaster.KmsKeyMaster(self.swift,
TEST_KMS_KEYMASTER_CONF)
# Verify that _get_root_secret_from_kms() was called with the
# correct parameters.
mock_get_root_secret_from_kms.assert_called_with(
TEST_KMS_KEYMASTER_CONF
)
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch.object(kms_keymaster.KmsKeyMaster, '_get_root_secret')
def test_get_root_secret_from_external_file(
self, mock_get_root_secret_from_kms, mock_readconf):
# Return valid Barbican configuration parameters.
mock_readconf.return_value = TEST_KMS_KEYMASTER_CONF
# Successful call with coarse _get_root_secret_from_kms() mock.
mock_get_root_secret_from_kms.return_value = (
base64.b64encode(b'x' * 32))
# Point to external config in proxy-server config.
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
# Verify that _get_root_secret_from_kms() was called with the
# correct parameters.
mock_get_root_secret_from_kms.assert_called_with(
TEST_KMS_KEYMASTER_CONF
)
self.assertEqual(mock_readconf.mock_calls, [
mock.call('PATH_TO_KEYMASTER_CONFIG_FILE', 'kms_keymaster')])
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config, mock_keystone_password):
# Successful call with finer grained mocks.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return valid Barbican configuration parameters.
'''
mock_readconf.return_value = TEST_KMS_KEYMASTER_CONF
'''
Verify that no exceptions are raised by the mocked functions.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(self.swift,
TEST_KMS_KEYMASTER_CONF)
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_invalid_key_id(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Invalid key ID.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['key_id'] = TEST_KMS_INVALID_KEY_ID
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though key id invalid')
except ValueError as e:
self.assertEqual(e.args[0],
ERR_MESSAGE_SECRET_INCORRECTLY_SPECIFIED)
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_nonexistent_key_id(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Nonexistent key.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['key_id'] = TEST_KMS_NONEXISTENT_KEY_ID
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though key id invalid')
except Exception as e:
expected_message = ('Key not found, uuid: ' +
TEST_KMS_NONEXISTENT_KEY_ID)
self.assertEqual(e.args[0], expected_message)
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_invalid_key_format(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Nonexistent key.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['key_id'] = TEST_KMS_OPAQUE_KEY_ID
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though key format invalid')
except ValueError:
pass
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_config_file_and_params(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Both external config file and config parameters specified.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['keymaster_config_path'] = (
'PATH_TO_KEYMASTER_CONFIG_FILE'
)
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(self.swift, kms_conf)
raise Exception('Success even though config invalid')
except Exception as e:
expected_message = ('keymaster_config_path is set, but there are '
'other config options specified:')
self.assertTrue(e.args[0].startswith(expected_message),
"Error message does not start with '%s'" %
expected_message)
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_invalid_username(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Invalid username.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['username'] = 'invaliduser'
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though username invalid')
except Unauthorized as e:
self.assertEqual(e.http_status, 401)
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_invalid_password(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Invalid password.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['password'] = 'invalidpassword'
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though password invalid')
except Unauthorized as e:
self.assertEqual(e.http_status, 401)
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_connect_failure_auth_url(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config, mock_keystone_password):
# Connect failure kms auth_url.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['auth_endpoint'] = TEST_KMS_CONNECT_FAILURE_URL
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though auth_url invalid')
except ConnectFailure:
pass
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_bad_auth_url(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Bad kms auth_url.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['auth_endpoint'] = TEST_KMS_NON_BARBICAN_URL
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though auth_url invalid')
except DiscoveryFailure:
pass
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_bad_user_domain_name(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config, mock_keystone_password):
# Bad user domain name with mocks.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['user_domain_name'] = (
TEST_KMS_INVALID_USER_DOMAIN_NAME)
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though api_version invalid')
except Unauthorized as e:
self.assertEqual(e.http_status, 401)
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_invalid_key_algorithm(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Nonexistent key.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['key_id'] = TEST_KMS_DES_KEY_ID
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though key format invalid')
except ValueError:
pass
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_invalid_key_length(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Nonexistent key.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['key_id'] = TEST_KMS_SHORT_KEY_ID
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though key format invalid')
except ValueError:
pass
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_mocked_castellan_keymanager_none_key(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,
mock_keystone_password):
# Nonexistent key.
mock_keystone_password.side_effect = (
mock_keystone_password_side_effect)
'''
Set side_effect functions.
'''
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
'''
Return invalid Barbican configuration parameters.
'''
kms_conf = dict(TEST_KMS_KEYMASTER_CONF)
kms_conf['key_id'] = TEST_KMS_NONE_KEY_ID
mock_readconf.return_value = kms_conf
'''
Verify that an exception is raised by the mocked function.
'''
try:
self.app = kms_keymaster.KmsKeyMaster(
self.swift, TEST_PROXYSERVER_CONF_EXTERNAL_KEYMASTER_CONF)
raise Exception('Success even though None key returned')
except ValueError:
pass
except Exception:
print("Unexpected error: %s" % sys.exc_info()[0])
raise
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword', MockPassword)
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_get_root_secret_multiple_keys(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config,):
config = dict(TEST_KMS_KEYMASTER_CONF)
config.update({
'key_id_foo': 'foo-valid_kms_key_id-123456',
'key_id_bar': 'bar-valid_kms_key_id-123456',
'key_id_baz': 'zz-valid_unicode_kms_key_id-123456',
'key_id_non_ascii': u'\N{SNOWMAN}_unicode_key_id',
'active_root_secret_id': 'foo'})
# Set side_effect functions.
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
# Return valid Barbican configuration parameters.
mock_readconf.return_value = config
self.app = kms_keymaster.KmsKeyMaster(self.swift,
config)
expected_secrets = {
None: b'vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv',
'foo': b'ffffffffffffffffffffffffffffffff',
'bar': b'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
'baz': b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
'non_ascii': b'\xe2\x98\x83' * 32}
self.assertDictEqual(self.app._root_secrets, expected_secrets)
self.assertEqual(self.app.active_secret_id, 'foo')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.'
'keystone_password.KeystonePassword', MockPassword)
@mock.patch('swift.common.middleware.crypto.kms_keymaster.cfg')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.options')
@mock.patch('swift.common.middleware.crypto.keymaster.readconf')
@mock.patch('swift.common.middleware.crypto.kms_keymaster.key_manager')
def test_get_root_secret_legacy_key_id(
self, mock_castellan_key_manager, mock_readconf,
mock_castellan_options, mock_oslo_config):
# Set side_effect functions.
mock_castellan_key_manager.API.side_effect = (
mock_castellan_api_side_effect)
mock_castellan_options.set_defaults.side_effect = (
mock_options_set_defaults_side_effect)
mock_oslo_config.ConfigOpts.side_effect = (
mock_config_opts_side_effect)
# Return valid Barbican configuration parameters.
mock_readconf.return_value = TEST_KMS_KEYMASTER_CONF
self.app = kms_keymaster.KmsKeyMaster(self.swift,
TEST_KMS_KEYMASTER_CONF)
expected_secrets = {None: b'vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv'}
self.assertDictEqual(self.app._root_secrets, expected_secrets)
self.assertIsNone(self.app.active_secret_id)
if __name__ == '__main__':
unittest.main()