barbican/barbican/tests/tasks/test_certificate_resources.py

1066 lines
40 KiB
Python

# Copyright (c) 2013-2014 Rackspace, Inc.
#
# 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 datetime
from Crypto.PublicKey import RSA
import mock
from OpenSSL import crypto
from barbican.common import exception as excep
from barbican.common import hrefs
from barbican.common import resources as res
from barbican.model import models
from barbican.model import repositories
from barbican.plugin.interface import certificate_manager as cert_man
from barbican.plugin.interface import secret_store
from barbican.tasks import certificate_resources as cert_res
from barbican.tasks import common
from barbican.tests import database_utils
from barbican.tests import utils
container_repo = repositories.get_container_repository()
secret_repo = repositories.get_secret_repository()
ca_repo = repositories.get_ca_repository()
project_ca_repo = repositories.get_project_ca_repository()
preferred_ca_repo = repositories.get_preferred_ca_repository()
project_repo = repositories.get_project_repository()
order_repo = repositories.get_order_repository()
class WhenPerformingPrivateOperations(utils.BaseTestCase,
utils.MockModelRepositoryMixin):
"""Tests private methods within certificate_resources.py."""
def setUp(self):
super(WhenPerformingPrivateOperations, self).setUp()
self.order_plugin_meta_repo = mock.MagicMock()
self.setup_order_plugin_meta_repository_mock(
self.order_plugin_meta_repo)
self.order_barbican_meta_repo = mock.MagicMock()
self.setup_order_barbican_meta_repository_mock(
self.order_barbican_meta_repo)
def test_get_plugin_meta(self):
class Value(object):
def __init__(self, value):
self.value = value
class OrderModel(object):
id = mock.ANY
order_plugin_metadata = {
"foo": Value(1),
"bar": Value(2),
}
order_model = OrderModel()
self.order_plugin_meta_repo.get_metadata_for_order.return_value = (
order_model.order_plugin_metadata
)
result = cert_res._get_plugin_meta(order_model)
self._assert_dict_equal(order_model.order_plugin_metadata, result)
def test_get_plugin_meta_with_empty_dict(self):
result = cert_res._get_plugin_meta(None)
self._assert_dict_equal({}, result)
def test_save_plugin_meta_w_mock_meta(self):
# Test dict for plugin meta data.
test_order_model = 'My order model'
test_plugin_meta = {"foo": 1}
cert_res._save_plugin_metadata(
test_order_model, test_plugin_meta)
self.order_plugin_meta_repo.save.assert_called_once_with(
test_plugin_meta, test_order_model)
def test_save_plugin_w_null_meta(self):
test_order_model = 'My order model'
# Test None for plugin meta data.
cert_res._save_plugin_metadata(
test_order_model, None)
self.order_plugin_meta_repo.save.assert_called_once_with(
{}, test_order_model)
def test_get_barbican_meta_with_empty_dict(self):
result = cert_res._get_barbican_meta(None)
self._assert_dict_equal({}, result)
def test_save_barbican_w_null_meta(self):
test_order_model = 'My order model'
# Test None for plugin meta data.
cert_res._save_barbican_metadata(
test_order_model, None)
self.order_barbican_meta_repo.save.assert_called_once_with(
{}, test_order_model)
def _assert_dict_equal(self, expected, test):
self.assertIsInstance(expected, dict)
self.assertIsInstance(test, dict)
if expected != test:
if len(expected) != len(test):
self.fail('Expected dict not same size as test dict')
unmatched_items = set(expected.items()) ^ set(test.items())
if len(unmatched_items):
self.fail('One or more items different '
'between the expected and test dicts')
class BaseCertificateRequestsTestCase(utils.BaseTestCase):
"""Base Certificate Case Test function """
def setUp(self):
super(BaseCertificateRequestsTestCase, self).setUp()
database_utils.setup_in_memory_db()
self.external_project_id = "56789"
self.project = res.get_or_create_project(self.external_project_id)
project_repo.save(self.project)
self.barbican_meta_dto = mock.MagicMock()
self.order_meta = {}
self.plugin_meta = {}
self.barbican_meta = {}
self.result = cert_man.ResultDTO(
cert_man.CertificateStatus.WAITING_FOR_CA
)
self.result_follow_on = common.FollowOnProcessingStatusDTO()
self.cert_plugin = mock.MagicMock()
self.cert_plugin.issue_certificate_request.return_value = self.result
self.cert_plugin.check_certificate_status.return_value = self.result
self.store_plugin = mock.MagicMock()
parsed_ca = {
'plugin_name': "cert_plugin",
'plugin_ca_id': "XXXX",
'name': "test ca",
'description': 'Test CA',
'ca_signing_certificate': 'ZZZZZ',
'intermediates': 'YYYYY'
}
self.ca = models.CertificateAuthority(parsed_ca)
ca_repo.create_from(self.ca)
self.ca_id = self.ca.id
# second ca for testing
parsed_ca = {
'plugin_name': "cert_plugin",
'plugin_ca_id': "XXXX2",
'name': "test ca2",
'description': 'Test CA2',
'ca_signing_certificate': 'ZZZZZ2',
'intermediates': 'YYYYY2'
}
self.ca2 = models.CertificateAuthority(parsed_ca)
ca_repo.create_from(self.ca2)
self.ca_id2 = self.ca2.id
# data for preferred CA and global preferred CA tests
# add those to the repo in those tests
self.pref_ca = models.PreferredCertificateAuthority(
self.project.id,
self.ca_id)
self.global_pref_ca = models.PreferredCertificateAuthority(
1,
self.ca_id)
# data for stored key cases
self.private_key = models.Secret()
self.private_key.secret_type = 'PRIVATE'
self.private_key.project_id = self.project.id
secret_repo.create_from(self.private_key)
self.public_key = models.Secret()
self.public_key.secret_type = 'PUBLIC'
self.public_key.project_id = self.project.id
secret_repo.create_from(self.public_key)
self.passphrase = models.Secret()
self.passphrase.secret_type = 'PASSPHRASE'
self.passphrase.project_id = self.project.id
secret_repo.create_from(self.passphrase)
self.private_key_value = None
self.public_key_value = "public_key"
self.passphrase_value = None
self.parsed_container_with_passphrase = {
'name': 'container name',
'type': 'rsa',
'secret_refs': [
{'name': 'private_key',
'secret_ref': 'https://localhost/secrets/' +
self.private_key.id},
{'name': 'public_key',
'secret_ref': 'https://localhost/secrets/' +
self.public_key.id},
{'name': 'private_key_passphrase',
'secret_ref': 'https://localhost/secrets/' +
self.passphrase.id}
]
}
self.parsed_container = {
'name': 'container name',
'type': 'rsa',
'secret_refs': [
{'name': 'private_key',
'secret_ref': 'https://localhost/secrets/' +
self.private_key.id},
{'name': 'public_key',
'secret_ref': 'https://localhost/secrets/' +
self.public_key.id}
]
}
self.container_with_passphrase = models.Container(
self.parsed_container_with_passphrase)
self.container_with_passphrase.project_id = self.project.id
container_repo.create_from(self.container_with_passphrase)
self.container = models.Container(self.parsed_container)
self.container.project_id = self.project.id
container_repo.create_from(self.container)
repositories.commit()
self.stored_key_meta = {
cert_man.REQUEST_TYPE:
cert_man.CertificateRequestType.STORED_KEY_REQUEST,
"container_ref":
"https://localhost/containers/" + self.container.id,
"subject_dn": "cn=host.example.com,ou=dev,ou=us,o=example.com"
}
self.order = models.Order()
self.order.meta = self.order_meta
self.order.project_id = self.project.id
self.order.order_barbican_meta = self.barbican_meta
self.order.type = 'certificate'
order_repo.create_from(self.order)
self._config_cert_plugin()
self._config_store_plugin()
self._config_cert_event_plugin()
self._config_save_meta_plugin()
self._config_get_meta_plugin()
self._config_save_barbican_meta_plugin()
self._config_get_barbican_meta_plugin()
self._config_barbican_meta_dto()
def tearDown(self):
super(BaseCertificateRequestsTestCase, self).tearDown()
database_utils.in_memory_cleanup()
self.cert_plugin_patcher.stop()
self.save_plugin_meta_patcher.stop()
self.get_plugin_meta_patcher.stop()
self.cert_event_plugin_patcher.stop()
self.barbican_meta_dto_patcher.stop()
self.save_barbican_barbican_meta_patcher.stop()
self.get_barbican_plugin_meta_patcher.stop()
self.store_plugin_patcher.stop()
def stored_key_side_effect(self, *args, **kwargs):
if args[0] == 'PRIVATE':
return secret_store.SecretDTO(
secret_store.SecretType.PRIVATE,
self.private_key_value,
None,
'application/octet-string',
None)
elif args[0] == 'PASSPHRASE':
return secret_store.SecretDTO(
secret_store.SecretType.PASSPHRASE,
self.passphrase_value,
None,
'application/octet-string',
None)
elif args[0] == 'PUBLIC':
return secret_store.SecretDTO(
secret_store.SecretType.PUBLIC,
self.public_key_value,
None,
'application/octet-string',
None)
else:
return None
def _test_should_return_waiting_for_ca(self, method_to_test):
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
method_to_test(
self.order, self.project, self.result_follow_on)
self.assertEqual(
common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_REQUEST_PENDING.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_REQUEST_PENDING.message,
self.result_follow_on.status_message)
def _test_should_return_certificate_generated(self, method_to_test):
self.result.status = cert_man.CertificateStatus.CERTIFICATE_GENERATED
method_to_test(
self.order, self.project, self.result_follow_on)
self.assertEqual(
common.RetryTasks.NO_ACTION_REQUIRED,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_CERT_GENERATED.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_CERT_GENERATED.message,
self.result_follow_on.status_message)
def _test_should_raise_client_data_issue_seen(self, method_to_test):
self.result.status = cert_man.CertificateStatus.CLIENT_DATA_ISSUE_SEEN
self.assertRaises(
cert_man.CertificateStatusClientDataIssue,
method_to_test,
self.order,
self.project,
self.result_follow_on
)
def _test_should_raise_status_not_supported(self, method_to_test):
self.result.status = "Legend of Link"
self.assertRaises(
cert_man.CertificateStatusNotSupported,
method_to_test,
self.order,
self.project,
self.result_follow_on
)
def _config_cert_plugin(self):
"""Mock the certificate plugin manager."""
cert_plugin_config = {
'return_value.get_plugin.return_value': self.cert_plugin,
'return_value.get_plugin_by_name.return_value': self.cert_plugin,
'return_value.get_plugin_by_ca_id.return_value': self.cert_plugin
}
self.cert_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.CertificatePluginManager',
**cert_plugin_config
)
self.cert_plugin_patcher.start()
def _config_store_plugin(self):
"""Mock the secret store plugin manager."""
store_plugin_config = {
'return_value.get_plugin_retrieve_delete.return_value':
self.store_plugin
}
self.store_plugin_patcher = mock.patch(
'barbican.plugin.interface.secret_store'
'.get_manager',
**store_plugin_config
)
self.store_plugin_patcher.start()
def _config_cert_event_plugin(self):
"""Mock the certificate event plugin manager."""
self.cert_event_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.EVENT_PLUGIN_MANAGER'
)
self.cert_event_plugin_patcher.start()
def _config_save_meta_plugin(self):
"""Mock the save plugin meta function."""
self.save_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._save_plugin_metadata'
)
self.mock_save_plugin = self.save_plugin_meta_patcher.start()
def _config_get_meta_plugin(self):
"""Mock the get plugin meta function."""
get_plugin_config = {'return_value': self.plugin_meta}
self.get_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._get_plugin_meta',
**get_plugin_config
)
self.get_plugin_meta_patcher.start()
def _config_save_barbican_meta_plugin(self):
"""Mock the save barbican plugin meta function."""
self.save_barbican_barbican_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._save_barbican_metadata'
)
self.mock_barbican_save_plugin = (
self.save_barbican_barbican_meta_patcher.start()
)
def _config_get_barbican_meta_plugin(self):
"""Mock the get barbican plugin meta function."""
get_barbican_plugin_config = {'return_value': self.barbican_meta}
self.get_barbican_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._get_barbican_meta',
**get_barbican_plugin_config
)
self.get_barbican_plugin_meta_patcher.start()
def _config_barbican_meta_dto(self):
"""Mock the BarbicanMetaDTO."""
get_plugin_config = {'return_value': self.barbican_meta_dto}
self.barbican_meta_dto_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.BarbicanMetaDTO',
**get_plugin_config
)
self.barbican_meta_dto_patcher.start()
class WhenIssuingCertificateRequests(BaseCertificateRequestsTestCase):
"""Tests the 'issue_certificate_request()' function."""
def setUp(self):
super(WhenIssuingCertificateRequests, self).setUp()
def tearDown(self):
super(WhenIssuingCertificateRequests, self).tearDown()
def test_should_return_waiting_for_ca(self):
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
def test_should_return_waiting_for_ca_as_retry(self):
# For a retry, the plugin-name to look up would have already been
# saved into the barbican metadata for the order, so just make sure
# we can retrieve it.
self.barbican_meta.update({'plugin_name': 'foo-plugin'})
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
def test_should_return_certificate_generated(self):
self._test_should_return_certificate_generated(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
def test_should_raise_client_data_issue_seen(self):
self._test_should_raise_client_data_issue_seen(
cert_res.issue_certificate_request)
def _do_pyopenssl_stored_key_request(self):
self.order_meta.update(self.stored_key_meta)
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
key_pem = crypto.dump_privatekey(
crypto.FILETYPE_PEM, pkey)
self.private_key_value = base64.b64encode(key_pem)
self.public_key_value = "public_key"
self.passphrase_value = None
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
def test_should_return_for_pyopenssl_stored_key(self):
self._do_pyopenssl_stored_key_request()
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta.get('generated_csr'))
# TODO(alee-3) Add tests to validate the request based on the validator
# code that dave-mccowan is adding.
def test_should_return_for_openssl_stored_key_ca_id_passed_in(self):
self.stored_key_meta['ca_id'] = self.ca_id2
self._do_pyopenssl_stored_key_request()
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta['generated_csr'])
def test_should_return_for_openssl_stored_key_pref_ca_defined(self):
preferred_ca_repo.create_from(self.pref_ca)
self._do_pyopenssl_stored_key_request()
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta['generated_csr'])
def test_should_return_for_openssl_stored_key_global_ca_defined(self):
preferred_ca_repo.create_from(self.global_pref_ca)
self._do_pyopenssl_stored_key_request()
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta['generated_csr'])
def test_should_return_for_pyopenssl_stored_key_with_passphrase(self):
self.order_meta.update(self.stored_key_meta)
self.order_meta['container_ref'] = (
"https://localhost/containers/" + self.container_with_passphrase.id
)
passphrase = "my secret passphrase"
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
key_pem = crypto.dump_privatekey(
crypto.FILETYPE_PEM,
pkey,
passphrase=passphrase.encode('utf-8')
)
self.private_key_value = base64.b64encode(key_pem)
self.public_key_value = "public_key"
self.passphrase_value = base64.b64encode(passphrase.encode('utf-8'))
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta['generated_csr'])
# TODO(alee-3) Add tests to validate the request based on the validator
# code that dave-mccowan is adding.
def test_should_return_for_pycrypto_stored_key_with_passphrase(self):
self.order_meta.update(self.stored_key_meta)
self.order_meta['container_ref'] = (
"https://localhost/containers/" + self.container_with_passphrase.id
)
passphrase = "my secret passphrase"
private_key = RSA.generate(2048, None, None, 65537)
public_key = private_key.publickey()
private_key_pem = private_key.exportKey('PEM', passphrase, 8)
self.private_key_value = base64.b64encode(private_key_pem)
public_key_pem = public_key.exportKey()
self.public_key_value = base64.b64encode(public_key_pem)
self.passphrase_value = base64.b64encode(passphrase.encode('utf-8'))
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta['generated_csr'])
# TODO(alee-3) Add tests to validate the request based on the validator
# code that dave-mccowan is adding.
def test_should_return_for_pycrypto_stored_key_without_passphrase(self):
self.order_meta.update(self.stored_key_meta)
private_key = RSA.generate(2048, None, None, 65537)
public_key = private_key.publickey()
self.private_key_value = base64.b64encode(
private_key.exportKey('PEM', None, 8))
self.public_key_value = base64.b64encode(public_key.exportKey())
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta['generated_csr'])
# TODO(alee-3) Add tests to validate the request based on the validator
# code that dave-mccowan is adding.
def test_should_raise_for_pycrypto_stored_key_no_container(self):
self.order_meta.update(self.stored_key_meta)
private_key = RSA.generate(2048, None, None, 65537)
public_key = private_key.publickey()
self.private_key_value = private_key.exportKey('PEM', None, 8)
self.public_key_value = public_key.exportKey()
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
container_repo.delete_project_entities(self.project.id)
self.assertRaises(excep.StoredKeyContainerNotFound,
cert_res.issue_certificate_request,
self.order,
self.project,
self.result_follow_on)
def test_should_raise_for_pycrypto_stored_key_no_private_key(self):
self.order_meta.update(self.stored_key_meta)
private_key = RSA.generate(2048, None, None, 65537)
public_key = private_key.publickey()
self.private_key_value = base64.b64encode(
private_key.exportKey('PEM', None, 8))
self.public_key_value = base64.b64encode(
public_key.exportKey())
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
secret_repo.delete_entity_by_id(
self.private_key.id, self.external_project_id)
self.assertRaises(excep.StoredKeyPrivateKeyNotFound,
cert_res.issue_certificate_request,
self.order,
self.project,
self.result_follow_on)
def test_should_return_for_pyopenssl_stored_key_with_extensions(self):
self.order_meta.update(self.stored_key_meta)
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
self.private_key_value = base64.b64encode(crypto.dump_privatekey(
crypto.FILETYPE_PEM, pkey))
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self.order_meta['extensions'] = 'my ASN.1 extensions structure here'
# TODO(alee-3) Add real extensions data here
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
cert_res.issue_certificate_request(self.order,
self.project,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(self.order.order_barbican_meta['generated_csr'])
# TODO(alee-3) Add tests to validate the request based on the validator
# code that dave-mccowan is adding.
# TODO(alee-3) Add tests to validate the extensions in the request
def test_should_raise_invalid_operation_seen(self):
self.result.status = cert_man.CertificateStatus.INVALID_OPERATION
self.assertRaises(
cert_man.CertificateStatusInvalidOperation,
cert_res.issue_certificate_request,
self.order,
self.project,
self.result_follow_on
)
def test_should_return_ca_unavailable_for_request(self):
retry_msec = 123
status_msg = 'Test status'
self.result.status = (
cert_man.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST)
self.result.retry_msec = retry_msec
self.result.status_message = status_msg
order_ref = hrefs.convert_order_to_href(self.order.id)
cert_res.issue_certificate_request(self.order,
self.project,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
epm = self.cert_event_plugin_patcher.target.EVENT_PLUGIN_MANAGER
epm.notify_ca_is_unavailable.assert_called_once_with(
self.project.id,
order_ref,
status_msg,
retry_msec
)
self._verify_issue_certificate_plugins_called()
self.assertEqual(
common.RetryTasks.INVOKE_SAME_TASK,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE.message,
self.result_follow_on.status_message)
def test_should_raise_status_not_supported(self):
self._test_should_raise_status_not_supported(
cert_res.issue_certificate_request)
def _verify_issue_certificate_plugins_called(self):
self.cert_plugin.issue_certificate_request.assert_called_once_with(
self.order.id,
self.order_meta,
self.plugin_meta,
self.barbican_meta_dto
)
self.mock_save_plugin.assert_called_once_with(
self.order,
self.plugin_meta
)
self.mock_barbican_save_plugin.assert_called_once_with(
self.order,
self.barbican_meta
)
class WhenCheckingCertificateRequests(BaseCertificateRequestsTestCase):
"""Tests the 'check_certificate_request()' function."""
def setUp(self):
super(WhenCheckingCertificateRequests, self).setUp()
def tearDown(self):
super(WhenCheckingCertificateRequests, self).tearDown()
def test_should_return_waiting_for_ca(self):
self._test_should_return_waiting_for_ca(
cert_res.check_certificate_request)
self._verify_check_certificate_plugins_called()
def test_should_return_certificate_generated(self):
self._test_should_return_certificate_generated(
cert_res.check_certificate_request)
self._verify_check_certificate_plugins_called()
def test_should_raise_client_data_issue_seen(self):
self._test_should_raise_client_data_issue_seen(
cert_res.check_certificate_request)
def test_should_raise_status_not_supported(self):
self._test_should_raise_status_not_supported(
cert_res.check_certificate_request)
def test_should_return_ca_unavailable_for_request(self):
retry_msec = 123
status_msg = 'Test status'
self.result.status = (
cert_man.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST)
self.result.retry_msec = retry_msec
self.result.status_message = status_msg
order_ref = hrefs.convert_order_to_href(self.order.id)
cert_res.check_certificate_request(self.order,
self.project,
self.result_follow_on)
self._verify_check_certificate_plugins_called()
epm = self.cert_event_plugin_patcher.target.EVENT_PLUGIN_MANAGER
epm.notify_ca_is_unavailable.assert_called_once_with(
self.project.id,
order_ref,
status_msg,
retry_msec
)
self.assertEqual(
common.RetryTasks.INVOKE_SAME_TASK,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_CHECK.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_CHECK.message,
self.result_follow_on.status_message)
def _do_pyopenssl_stored_key_request(self):
self.order_meta.update(self.stored_key_meta)
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
key_pem = crypto.dump_privatekey(
crypto.FILETYPE_PEM, pkey)
self.private_key_value = base64.b64encode(key_pem)
self.public_key_value = "public_key"
self.passphrase_value = None
self.store_plugin.get_secret.side_effect = self.stored_key_side_effect
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._test_should_return_certificate_generated(
cert_res.check_certificate_request)
def test_should_return_for_pyopenssl_stored_key(self):
self._do_pyopenssl_stored_key_request()
self._verify_check_certificate_plugins_called()
self.assertIsNotNone(
self.order.order_barbican_meta.get('generated_csr'))
def _verify_check_certificate_plugins_called(self):
self.cert_plugin.check_certificate_status.assert_called_once_with(
self.order.id,
self.order_meta,
self.plugin_meta,
self.barbican_meta_dto
)
self.mock_save_plugin.assert_called_with(
self.order,
self.plugin_meta
)
class WhenCreatingSubordinateCAs(utils.BaseTestCase):
"""Tests the 'create_subordinate_ca()' function."""
def setUp(self):
super(WhenCreatingSubordinateCAs, self).setUp()
self.project = res.get_or_create_project('12345')
self.project2 = res.get_or_create_project('56789')
self.subject_name = "cn=subca1 signing certificate, o=example.com"
self.creator_id = "user12345"
self.name = "Subordinate CA #1"
self.description = "This is a test subordinate CA"
self.plugin_name = "dogtag_plugin"
# create parent ca
expiration = (datetime.datetime.utcnow() +
datetime.timedelta(minutes=10))
parsed_ca = {'plugin_name': self.plugin_name,
'plugin_ca_id': 'ca_master',
'expiration': expiration.isoformat(),
'name': 'Dogtag CA',
'description': 'Master CA for Dogtag plugin',
'ca_signing_certificate': 'XXXXX',
'intermediates': 'YYYYY'}
self.parent_ca = models.CertificateAuthority(parsed_ca)
ca_repo.create_from(self.parent_ca)
self.parent_ca_ref = 'https://localhost:6311/cas/' + self.parent_ca.id
self.new_ca_dict = {
'plugin_ca_id': 'ca_subordinate',
'expiration': expiration.isoformat(),
'name': 'Dogtag Subordinate CA',
'description': 'Subordinate CA for Dogtag plugin',
'ca_signing_certificate': 'XXXXX',
'intermediates': 'YYYYY',
}
# mock plugin and calls to plugin
self.cert_plugin = mock.MagicMock()
self.cert_plugin.supports_create_ca.return_value = True
self.cert_plugin.create_ca.return_value = self.new_ca_dict
self._config_cert_plugin()
def tearDown(self):
super(WhenCreatingSubordinateCAs, self).tearDown()
self.cert_plugin_patcher.stop()
def test_should_create_subordinate_ca(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
self.assertIsInstance(subca, models.CertificateAuthority)
self.assertEqual(self.project.id, subca.project_id)
self.assertEqual(self.creator_id, subca.creator_id)
self.assertEqual(self.plugin_name, subca.plugin_name)
def test_should_raise_invalid_parent_ca(self):
self.parent_ca_ref = 'https://localhost:6311/cas/' + "BAD-CA-REF"
self.assertRaises(
excep.InvalidParentCA,
cert_res.create_subordinate_ca,
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
def test_should_raise_unauthorized_parent_ca(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project2,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
subca_ref = hrefs.convert_certificate_authority_to_href(subca.id)
self.assertRaises(
excep.UnauthorizedSubCA,
cert_res.create_subordinate_ca,
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=subca_ref,
creator_id=self.creator_id)
def test_should_raise_subcas_not_supported(self):
self.cert_plugin.supports_create_ca.return_value = False
self.assertRaises(
excep.SubCAsNotSupported,
cert_res.create_subordinate_ca,
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
def test_should_raise_subcas_not_created(self):
self.cert_plugin.create_ca.return_value = None
self.assertRaises(
excep.SubCANotCreated,
cert_res.create_subordinate_ca,
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
def test_should_delete_subca(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
self.assertIsInstance(subca, models.CertificateAuthority)
cert_res.delete_subordinate_ca(self.project.external_id, subca)
self.cert_plugin.delete_ca.assert_called_once_with(subca.plugin_ca_id)
def test_should_delete_subca_and_all_related_db_entities(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
project_ca = models.ProjectCertificateAuthority(
self.project.id,
subca.id
)
project_ca_repo.create_from(project_ca)
preferred_ca = models.PreferredCertificateAuthority(
self.project.id,
subca.id)
preferred_ca_repo.create_from(preferred_ca)
cert_res.delete_subordinate_ca(self.project.external_id, subca)
self.cert_plugin.delete_ca.assert_called_once_with(subca.plugin_ca_id)
def test_should_raise_when_delete_pref_subca_with_other_project_ca(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
project_ca = models.ProjectCertificateAuthority(
self.project.id,
subca.id
)
project_ca_repo.create_from(project_ca)
preferred_ca = models.PreferredCertificateAuthority(
self.project.id,
subca.id)
preferred_ca_repo.create_from(preferred_ca)
subca2 = cert_res.create_subordinate_ca(
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
project_ca2 = models.ProjectCertificateAuthority(
self.project.id,
subca2.id
)
project_ca_repo.create_from(project_ca2)
self.assertRaises(
excep.CannotDeletePreferredCA,
cert_res.delete_subordinate_ca,
self.project.external_id,
subca
)
def test_should_raise_cannot_delete_base_ca(self):
self.assertRaises(
excep.CannotDeleteBaseCA,
cert_res.delete_subordinate_ca,
self.project.external_id,
self.parent_ca
)
def test_should_raise_unauthorized_subca_delete(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
self.assertRaises(
excep.UnauthorizedSubCA,
cert_res.delete_subordinate_ca,
self.project2.external_id,
subca
)
def _config_cert_plugin(self):
"""Mock the certificate plugin manager."""
cert_plugin_config = {
'return_value.get_plugin.return_value': self.cert_plugin,
'return_value.get_plugin_by_name.return_value': self.cert_plugin,
'return_value.get_plugin_by_ca_id.return_value': self.cert_plugin
}
self.cert_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.CertificatePluginManager',
**cert_plugin_config
)
self.cert_plugin_patcher.start()