Merge "Add ability to add and list CAs"
This commit is contained in:
56
barbicanclient/barbican_cli/cas.py
Normal file
56
barbicanclient/barbican_cli/cas.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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.
|
||||
"""
|
||||
Command-line interface sub-commands related to secrets.
|
||||
"""
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
|
||||
from barbicanclient import cas
|
||||
|
||||
|
||||
class GetCA(show.ShowOne):
|
||||
"""Retrieve a CA by providing its URI."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetCA, self).get_parser(prog_name)
|
||||
parser.add_argument('URI', help='The URI reference for the CA.')
|
||||
return parser
|
||||
|
||||
def take_action(self, args):
|
||||
entity = self.app.client.cas.get(ca_ref=args.URI)
|
||||
return entity._get_formatted_entity()
|
||||
|
||||
|
||||
class ListCA(lister.Lister):
|
||||
"""List cas."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListCA, self).get_parser(prog_name)
|
||||
parser.add_argument('--limit', '-l', default=10,
|
||||
help='specify the limit to the number of items '
|
||||
'to list per page (default: %(default)s; '
|
||||
'maximum: 100)',
|
||||
type=int)
|
||||
parser.add_argument('--offset', '-o', default=0,
|
||||
help='specify the page offset '
|
||||
'(default: %(default)s)',
|
||||
type=int)
|
||||
parser.add_argument('--name', '-n', default=None,
|
||||
help='specify the secret name '
|
||||
'(default: %(default)s)')
|
||||
return parser
|
||||
|
||||
def take_action(self, args):
|
||||
obj_list = self.app.client.cas.list(args.limit, args.offset, args.name)
|
||||
return cas.CA._list_objects(obj_list)
|
||||
236
barbicanclient/cas.py
Normal file
236
barbicanclient/cas.py
Normal file
@@ -0,0 +1,236 @@
|
||||
# Copyright (c) 2015 Red Hat 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 functools
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from oslo_utils.timeutils import parse_isotime
|
||||
|
||||
from barbicanclient import base
|
||||
from barbicanclient import formatter
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def lazy(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, *args):
|
||||
self._fill_lazy_properties()
|
||||
return func(self, *args)
|
||||
return wrapper
|
||||
|
||||
|
||||
class CAFormatter(formatter.EntityFormatter):
|
||||
|
||||
columns = ("CA href",
|
||||
"Name",
|
||||
"Description",
|
||||
"Created",
|
||||
"Updated",
|
||||
"Status",
|
||||
"Plugin Name",
|
||||
"Plugin CA ID",
|
||||
"Expiration"
|
||||
)
|
||||
|
||||
def _get_formatted_data(self):
|
||||
data = (self.ca_ref,
|
||||
self.name,
|
||||
self.description,
|
||||
self.created,
|
||||
self.updated,
|
||||
self.status,
|
||||
self.plugin_name,
|
||||
self.plugin_ca_id,
|
||||
self.expiration
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
class CA(CAFormatter):
|
||||
"""
|
||||
CAs represent certificate authorities or subCAs with which the Barbican
|
||||
service is configured to interact.
|
||||
"""
|
||||
_entity = 'cas'
|
||||
|
||||
def __init__(self, api, meta=None, expiration=None,
|
||||
plugin_name=None, plugin_ca_id=None,
|
||||
ca_ref=None, created=None, updated=None,
|
||||
status=None, creator_id=None):
|
||||
"""
|
||||
CA objects should not be instantiated directly. You should use
|
||||
the `create` or `get` methods of the
|
||||
:class:`barbicanclient.cas.CAManager` instead.
|
||||
"""
|
||||
self._api = api
|
||||
self._ca_ref = ca_ref
|
||||
self._fill_from_data(
|
||||
meta=meta,
|
||||
expiration=expiration,
|
||||
plugin_name=plugin_name,
|
||||
plugin_ca_id=plugin_ca_id,
|
||||
created=created,
|
||||
updated=updated,
|
||||
status=status,
|
||||
creator_id=creator_id
|
||||
)
|
||||
|
||||
@property
|
||||
def ca_ref(self):
|
||||
return self._ca_ref
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def expiration(self):
|
||||
return self._expiration
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def description(self):
|
||||
return self._description
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def plugin_name(self):
|
||||
return self._plugin_name
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def plugin_ca_id(self):
|
||||
return self._plugin_ca_id
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def created(self):
|
||||
return self._created
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def updated(self):
|
||||
return self._updated
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def status(self):
|
||||
return self._status
|
||||
|
||||
def _fill_from_data(self, meta=None, expiration=None,
|
||||
plugin_name=None, plugin_ca_id=None, created=None,
|
||||
updated=None, status=None, creator_id=None):
|
||||
if meta:
|
||||
for s in meta:
|
||||
key = list(s.keys())[0]
|
||||
value = list(s.values())[0]
|
||||
if key == 'name':
|
||||
self._name = value
|
||||
if key == 'description':
|
||||
self._description = value
|
||||
self._plugin_name = plugin_name
|
||||
self._plugin_ca_id = plugin_ca_id
|
||||
self._expiration = expiration
|
||||
self._creator_id = creator_id
|
||||
if self._expiration:
|
||||
self._expiration = parse_isotime(self._expiration)
|
||||
if self._ca_ref:
|
||||
self._status = status
|
||||
self._created = created
|
||||
self._updated = updated
|
||||
if self._created:
|
||||
self._created = parse_isotime(self._created)
|
||||
if self._updated:
|
||||
self._updated = parse_isotime(self._updated)
|
||||
else:
|
||||
self._status = None
|
||||
self._created = None
|
||||
self._updated = None
|
||||
|
||||
def _fill_lazy_properties(self):
|
||||
if self._ca_ref and not self._plugin_name:
|
||||
result = self._api.get(self._ca_ref)
|
||||
self._fill_from_data(
|
||||
meta=result.get('meta'),
|
||||
expiration=result.get('expiration'),
|
||||
plugin_name=result.get('plugin_name'),
|
||||
plugin_ca_id=result.get('plugin_ca_id'),
|
||||
created=result.get('created'),
|
||||
updated=result.get('updated'),
|
||||
status=result.get('status')
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
if self._ca_ref:
|
||||
return 'CA(ca_ref="{0}")'.format(self._ca_ref)
|
||||
return 'CA(name="{0}")'.format(self._name)
|
||||
|
||||
|
||||
class CAManager(base.BaseEntityManager):
|
||||
"""Entity Manager for Secret entities"""
|
||||
|
||||
def __init__(self, api):
|
||||
super(CAManager, self).__init__(api, 'cas')
|
||||
|
||||
def get(self, ca_ref):
|
||||
"""
|
||||
Retrieve an existing CA from Barbican
|
||||
|
||||
:param str ca_ref: Full HATEOAS reference to a CA
|
||||
:returns: CA object retrieved from Barbican
|
||||
:rtype: :class:`barbicanclient.cas.CA`
|
||||
:raises barbicanclient.exceptions.HTTPAuthError: 401 Responses
|
||||
:raises barbicanclient.exceptions.HTTPClientError: 4xx Responses
|
||||
:raises barbicanclient.exceptions.HTTPServerError: 5xx Responses
|
||||
"""
|
||||
LOG.debug("Getting ca - CA href: {0}".format(ca_ref))
|
||||
base.validate_ref(ca_ref, 'CA')
|
||||
return CA(
|
||||
api=self._api,
|
||||
ca_ref=ca_ref
|
||||
)
|
||||
|
||||
def list(self, limit=10, offset=0, name=None):
|
||||
"""
|
||||
List CAs for the project
|
||||
|
||||
This method uses the limit and offset parameters for paging,
|
||||
and also supports filtering.
|
||||
|
||||
:param limit: Max number of CAs returned
|
||||
:param offset: Offset secrets to begin list
|
||||
:param name: Name filter for the list
|
||||
:returns: list of CA objects that satisfy the provided filter
|
||||
criteria.
|
||||
:rtype: list
|
||||
:raises barbicanclient.exceptions.HTTPAuthError: 401 Responses
|
||||
:raises barbicanclient.exceptions.HTTPClientError: 4xx Responses
|
||||
:raises barbicanclient.exceptions.HTTPServerError: 5xx Responses
|
||||
"""
|
||||
LOG.debug('Listing CAs - offset {0} limit {1}'.format(offset, limit))
|
||||
params = {'limit': limit, 'offset': offset}
|
||||
if name:
|
||||
params['name'] = name
|
||||
|
||||
response = self._api.get(self._entity, params=params)
|
||||
|
||||
return [
|
||||
CA(api=self._api, ca_ref=s)
|
||||
for s in response.get('cas', [])
|
||||
]
|
||||
@@ -20,6 +20,7 @@ from keystoneclient import adapter
|
||||
from keystoneclient.auth.base import BaseAuthPlugin
|
||||
from keystoneclient import session as ks_session
|
||||
|
||||
from barbicanclient import cas
|
||||
from barbicanclient import containers
|
||||
from barbicanclient import exceptions
|
||||
from barbicanclient._i18n import _
|
||||
@@ -167,6 +168,7 @@ class Client(object):
|
||||
self.secrets = secrets.SecretManager(httpclient)
|
||||
self.orders = orders.OrderManager(httpclient)
|
||||
self.containers = containers.ContainerManager(httpclient)
|
||||
self.cas = cas.CAManager(httpclient)
|
||||
|
||||
|
||||
def env(*vars, **kwargs):
|
||||
|
||||
113
barbicanclient/tests/test_cas.py
Normal file
113
barbicanclient/tests/test_cas.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# Copyright (c) 2013 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.
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from barbicanclient.tests import test_client
|
||||
from barbicanclient import cas
|
||||
|
||||
|
||||
class CAData(object):
|
||||
def __init__(self):
|
||||
self.name = u'Test CA'
|
||||
self.description = u'Test CA description'
|
||||
self.plugin_name = u'Test CA Plugin'
|
||||
self.plugin_ca_id = 'plugin_uuid'
|
||||
|
||||
now = timeutils.utcnow()
|
||||
self.expiration = str(now)
|
||||
self.created = str(now)
|
||||
|
||||
self.meta = [
|
||||
{'name': self.name},
|
||||
{'description': self.description}
|
||||
]
|
||||
|
||||
self.ca_dict = {'meta': self.meta,
|
||||
'status': u'ACTIVE',
|
||||
'plugin_name': self.plugin_name,
|
||||
'plugin_ca_id': self.plugin_ca_id,
|
||||
'created': self.created}
|
||||
|
||||
def get_dict(self, ca_ref=None):
|
||||
ca = self.ca_dict
|
||||
if ca_ref:
|
||||
ca['ca_ref'] = ca_ref
|
||||
return ca
|
||||
|
||||
|
||||
class WhenTestingCAs(test_client.BaseEntityResource):
|
||||
|
||||
def setUp(self):
|
||||
self._setUp('cas')
|
||||
|
||||
self.ca = CAData()
|
||||
self.manager = self.client.cas
|
||||
|
||||
def test_should_get_lazy(self):
|
||||
data = self.ca.get_dict(self.entity_href)
|
||||
m = self.responses.get(self.entity_href, json=data)
|
||||
|
||||
ca = self.manager.get(ca_ref=self.entity_href)
|
||||
self.assertIsInstance(ca, cas.CA)
|
||||
self.assertEqual(self.entity_href, ca._ca_ref)
|
||||
|
||||
# Verify GET wasn't called yet
|
||||
self.assertFalse(m.called)
|
||||
|
||||
# Check an attribute to trigger lazy-load
|
||||
self.assertEqual(self.ca.plugin_ca_id, ca.plugin_ca_id)
|
||||
|
||||
# Verify the correct URL was used to make the GET call
|
||||
self.assertEqual(self.entity_href, m.last_request.url)
|
||||
|
||||
def test_should_get_lazy_in_meta(self):
|
||||
data = self.ca.get_dict(self.entity_href)
|
||||
m = self.responses.get(self.entity_href, json=data)
|
||||
|
||||
ca = self.manager.get(ca_ref=self.entity_href)
|
||||
self.assertIsInstance(ca, cas.CA)
|
||||
self.assertEqual(self.entity_href, ca._ca_ref)
|
||||
|
||||
# Verify GET wasn't called yet
|
||||
self.assertFalse(m.called)
|
||||
|
||||
# Check an attribute in meta to trigger lazy-load
|
||||
self.assertEqual(self.ca.name, ca.name)
|
||||
|
||||
# Verify the correct URL was used to make the GET call
|
||||
self.assertEqual(self.entity_href, m.last_request.url)
|
||||
|
||||
def test_should_get_list(self):
|
||||
ca_resp = self.entity_href
|
||||
|
||||
data = {"cas": [ca_resp for v in range(3)]}
|
||||
m = self.responses.get(self.entity_base, json=data)
|
||||
|
||||
ca_list = self.manager.list(limit=10, offset=5)
|
||||
self.assertTrue(len(ca_list) == 3)
|
||||
self.assertIsInstance(ca_list[0], cas.CA)
|
||||
self.assertEqual(self.entity_href, ca_list[0].ca_ref)
|
||||
|
||||
# Verify the correct URL was used to make the call.
|
||||
self.assertEqual(self.entity_base,
|
||||
m.last_request.url.split('?')[0])
|
||||
|
||||
# Verify that correct information was sent in the call.
|
||||
self.assertEqual(['10'], m.last_request.qs['limit'])
|
||||
self.assertEqual(['5'], m.last_request.qs['offset'])
|
||||
|
||||
def test_should_fail_get_invalid_ca(self):
|
||||
self.assertRaises(ValueError, self.manager.get,
|
||||
**{'ca_ref': '12345'})
|
||||
@@ -47,6 +47,15 @@ Containers
|
||||
.. autoclass:: barbicanclient.containers.CertificateContainer
|
||||
:members:
|
||||
|
||||
Certificate Authorities
|
||||
=======================
|
||||
|
||||
.. autoclass:: barbicanclient.cas.CAManager
|
||||
:members:
|
||||
|
||||
.. autoclass:: barbicanclient.cas.CA
|
||||
:members:
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ barbican.client =
|
||||
container_list = barbicanclient.barbican_cli.containers:ListContainer
|
||||
container_create = barbicanclient.barbican_cli.containers:CreateContainer
|
||||
|
||||
ca_get = barbicanclient.barbican_cli.cas:GetCA
|
||||
ca_list = barbicanclient.barbican_cli.cas:ListCA
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
|
||||
Reference in New Issue
Block a user