Copy octavia.certmgr to Castellan

Change-Id: I6971735681cb31bb66fc8d52d2f46fdfca8abebe
This commit is contained in:
Adam Harwell 2015-02-16 11:38:57 -06:00
parent 2271737fd0
commit f8e6be10bf
11 changed files with 482 additions and 0 deletions

View File

45
castellan/certmgr/cert.py Normal file
View File

@ -0,0 +1,45 @@
# Copyright 2014, 2015 Rackspace US, 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.
"""
Base Certificate Class
"""
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class Cert(object):
"""Base class to represent all certificates."""
@abc.abstractmethod
def get_certificate(self):
"""Returns the certificate."""
pass
@abc.abstractmethod
def get_intermediates(self):
"""Returns the intermediate certificates."""
pass
@abc.abstractmethod
def get_private_key(self):
"""Returns the private key for the certificate."""
pass
@abc.abstractmethod
def get_private_key_passphrase(self):
"""Returns the passphrase for the private key."""
pass

View File

@ -0,0 +1,60 @@
# Copyright 2014, 2015 Rackspace US, 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.
"""
Certificate manager API
"""
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class CertManager(object):
"""Base Certificate Manager Interface
A Cert Manager is responsible for managing certificates for TLS. A Cert
Manager is responsible for storing, reading, and deleting certs.
"""
@abc.abstractmethod
def store_cert(self, ctxt, certificate, private_key, intermediates=None,
private_key_passphrase=None, **kwargs):
"""Stores (i.e., registers) a cert with the cert manager.
This method stores the specified cert and returns its UUID that
identifies it within the cert manager.
If storage of the certificate data fails, a CertificateStorageException
should be raised.
"""
pass
@abc.abstractmethod
def get_cert(self, ctxt, cert_ref, check_only=False, **kwargs):
"""Retrieves the specified cert.
If check_only is True, don't perform any sort of registration.
If the specified cert does not exist, a CertificateStorageException
should be raised.
"""
pass
@abc.abstractmethod
def delete_cert(self, ctxt, cert_ref, **kwargs):
"""Deletes the specified cert.
If the specified cert does not exist, a CertificateStorageException
should be raised.
"""
pass

View File

@ -0,0 +1,35 @@
# Copyright 2014, 2015 Rackspace US, 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.
"""
Certificate manager implementation that raises NotImplementedError
"""
from castellan.certmgr import cert_mgr
class NotImplementedCertManager(cert_mgr.CertManager):
"""Cert Manager implementation that raises NotImplementedError for all ops.
"""
def store_cert(self, ctxt, certificate, private_key, intermediates=None,
private_key_passphrase=None, **kwargs):
raise NotImplementedError()
def get_cert(self, ctxt, cert_ref, check_only=False, **kwargs):
raise NotImplementedError()
def delete_cert(self, ctxt, cert_ref, **kwargs):
raise NotImplementedError()

View File

View File

@ -0,0 +1,24 @@
# Copyright 2011 Justin Santa Barbara
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# 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.
"""Implementation of a fake key manager."""
from castellan.tests.certmgr import mock_cert_mgr
def fake_api():
return mock_cert_mgr.MockCertManager()

View File

@ -0,0 +1,53 @@
# Copyright 2014, 2015 Rackspace US, 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.
"""
Mock Certificate Class
"""
from castellan.certmgr import cert
class MockCert(cert.Cert):
"""Mock class to represent a certificate."""
def __init__(self, certificate=None, intermediates=None, private_key=None,
private_key_passphrase=None):
self.certificate = certificate
self.intermediates = intermediates
self.private_key = private_key
self.private_key_passphrase = private_key_passphrase
def get_certificate(self):
"""Returns the certificate."""
return self.certificate
def get_intermediates(self):
"""Returns the intermediate certificates."""
return self.intermediates
def get_private_key(self):
"""Returns the private key for the certificate."""
return self.private_key
def get_private_key_passphrase(self):
"""Returns the passphrase for the private key."""
return self.private_key_passphrase
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
else:
return False
def __ne__(self, other):
return not self.__eq__(other)

View File

@ -0,0 +1,100 @@
# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory
# All Rights Reserved.
#
# 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.
"""
A mock implementation of a cert manager that stores certs in a dictionary.
This cert manager implementation is primarily intended for testing. In
particular, it does not store certs persistently. Lack of a centralized cert
store also makes this implementation unsuitable for use among different
services.
Note: Instantiating this class multiple times will create separate cert stores.
Certs created in one instance will not be accessible from other instances of
this class.
"""
import uuid
from castellan.certmgr import cert_mgr
from castellan.common import exception
from castellan.tests.certmgr import mock_cert
class MockCertManager(cert_mgr.CertManager):
"""Mocking manager for integration tests.
This mock cert manager implementation supports all the methods specified
by the cert manager interface. This implementation stores certs within a
dictionary, and as a result, it is not acceptable for use across different
services. Side effects (e.g., raising exceptions) for each method are
handled as specified by the cert manager interface.
This cert manager is not suitable for use in production deployments.
"""
def __init__(self):
self.certs = {}
def _generate_cert_id(self):
cert_id = str(uuid.uuid4())
while cert_id in self.certs:
cert_id = str(uuid.uuid4())
return cert_id
def store_cert(self, ctxt, certificate, private_key, intermediates=None,
private_key_passphrase=None, **kwargs):
"""Stores a certificate.
This implementation returns a UUID for the created cert. A
Forbidden exception is raised if the specified context is None.
"""
if ctxt is None:
raise exception.Forbidden()
cert_id = self._generate_cert_id()
cert = mock_cert.MockCert(
certificate=certificate,
private_key=private_key,
intermediates=intermediates,
private_key_passphrase=private_key_passphrase
)
self.certs[cert_id] = cert
return cert_id
def get_cert(self, ctxt, cert_id, **kwargs):
"""Retrieves the cert identified by the specified id.
This implementation returns the cert that is associated with the
specified UUID. A Forbidden exception is raised if the specified
context is None; a KeyError is raised if the UUID is invalid.
"""
if ctxt is None:
raise exception.Forbidden()
return self.certs[cert_id]
def delete_cert(self, ctxt, cert_id, **kwargs):
"""Deletes the cert identified by the specified id.
A Forbidden exception is raised if the context is None and a
KeyError is raised if the UUID is invalid.
"""
if ctxt is None:
raise exception.Forbidden()
del self.certs[cert_id]

View File

@ -0,0 +1,33 @@
# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory
# All Rights Reserved.
#
# 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.
"""
Test cases for the cert manager.
"""
from castellan.tests import base
class CertManagerTestCase(base.TestCase):
def __init__(self, *args, **kwargs):
super(CertManagerTestCase, self).__init__(*args, **kwargs)
def _create_cert_manager(self):
raise NotImplementedError()
def setUp(self):
super(CertManagerTestCase, self).setUp()
self.cert_mgr = self._create_cert_manager()

View File

@ -0,0 +1,90 @@
# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory
# All Rights Reserved.
#
# 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.
"""
Test cases for the mock cert manager.
"""
from castellan.common import exception
from castellan import context
from castellan.tests.certmgr import mock_cert
from castellan.tests.certmgr import mock_cert_mgr
from castellan.tests.certmgr import test_cert_mgr
class MockCertManagerTestCase(test_cert_mgr.CertManagerTestCase):
def _create_cert_manager(self):
return mock_cert_mgr.MockCertManager()
def setUp(self):
super(MockCertManagerTestCase, self).setUp()
self.ctxt = context.RequestContext('fake', 'fake')
self.certificate = "This is a certificate. I swear."
self.intermediates = "This is a list of intermediates. Really."
self.private_key = "Don't look at me!"
self.private_key_passphrase = "hunter2"
def test_store_cert(self):
_cert = mock_cert.MockCert(
certificate=self.certificate,
private_key=self.private_key,
intermediates=self.intermediates,
private_key_passphrase=self.private_key_passphrase
)
cert_id = self.cert_mgr.store_cert(
ctxt=self.ctxt,
certificate=self.certificate,
private_key=self.private_key,
intermediates=self.intermediates,
private_key_passphrase=self.private_key_passphrase
)
actual_cert = self.cert_mgr.get_cert(self.ctxt, cert_id)
self.assertEqual(_cert, actual_cert)
def test_store_null_context(self):
self.assertRaises(exception.Forbidden,
self.cert_mgr.store_cert, None, None, None)
def test_get_cert(self):
pass
def test_get_null_context(self):
self.assertRaises(exception.Forbidden,
self.cert_mgr.get_cert, None, None)
def test_get_unknown_cert(self):
self.assertRaises(KeyError, self.cert_mgr.get_cert, self.ctxt, None)
def test_delete_cert(self):
cert_id = self.cert_mgr.store_cert(
ctxt=self.ctxt,
certificate=self.certificate,
private_key=self.private_key,
intermediates=self.intermediates,
private_key_passphrase=self.private_key_passphrase
)
self.cert_mgr.delete_cert(self.ctxt, cert_id)
self.assertRaises(KeyError, self.cert_mgr.get_cert, self.ctxt, cert_id)
def test_delete_null_context(self):
self.assertRaises(exception.Forbidden,
self.cert_mgr.delete_cert, None, None)
def test_delete_unknown_cert(self):
self.assertRaises(KeyError, self.cert_mgr.delete_cert, self.ctxt, None)

View File

@ -0,0 +1,42 @@
# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory
# All Rights Reserved.
#
# 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.
"""
Test cases for the not implemented cert manager.
"""
from castellan.certmgr import not_implemented_cert_mgr
from castellan.tests.certmgr import test_cert_mgr
class NotImplementedCertManagerTestCase(test_cert_mgr.CertManagerTestCase):
def _create_cert_manager(self):
return not_implemented_cert_mgr.NotImplementedCertManager()
def setUp(self):
super(NotImplementedCertManagerTestCase, self).setUp()
def test_store_cert(self):
self.assertRaises(NotImplementedError,
self.cert_mgr.store_cert, None, None, None)
def test_get_cert(self):
self.assertRaises(NotImplementedError,
self.cert_mgr.get_cert, None, None)
def test_delete_cert(self):
self.assertRaises(NotImplementedError,
self.cert_mgr.delete_cert, None, None)