diff options
author | Thomas Herve <thomas.herve@enovance.com> | 2015-05-01 15:45:38 +0200 |
---|---|---|
committer | Thomas Herve <thomas.herve@enovance.com> | 2015-05-09 10:42:01 +0200 |
commit | b5ef798446b4fc0b410641ee8c5653ded91a437a (patch) | |
tree | c7cc9ef95681c290c3207eaa2e129ec5b5f47221 | |
parent | 988c1380ff49b3d267bb64c71699708794966fd5 (diff) | |
download | python-barbicanclient-b5ef798446b4fc0b410641ee8c5653ded91a437a.tar.gz |
Add support for certificate order
This adds the ability to create and list certificate orders, using new
parameters for order create a specific handling for listing.
Closes-Bug: #1451458
Change-Id: I1fd2ec5f96d335d2c008d290a09e1133ff03e94c
-rw-r--r-- | barbicanclient/barbican_cli/orders.py | 40 | ||||
-rw-r--r-- | barbicanclient/orders.py | 99 | ||||
-rw-r--r-- | barbicanclient/tests/test_orders.py | 87 |
3 files changed, 215 insertions, 11 deletions
diff --git a/barbicanclient/barbican_cli/orders.py b/barbicanclient/barbican_cli/orders.py index d86bd66..60c81a6 100644 --- a/barbicanclient/barbican_cli/orders.py +++ b/barbicanclient/barbican_cli/orders.py @@ -47,14 +47,44 @@ class CreateOrder(show.ShowOne): parser.add_argument('--expiration', '-x', help='the expiration ' 'time for the secret in ISO 8601 format.') + parser.add_argument('--request-type', + help='the type of the certificate request.') + parser.add_argument('--subject-dn', + help='the subject of the certificate.') + parser.add_argument('--source-container-ref', + help='the source of the certificate when using ' + 'stored-key requests.') + parser.add_argument('--ca-id', + help='the identifier of the CA to use for the ' + 'certificate request.') + parser.add_argument('--profile', + help='the profile of certificate to use.') + parser.add_argument('--request-file', + help='the file containing the CSR.') return parser def take_action(self, args): - entity = self.app.client.orders.create( - name=args.name, type=args.type, - payload_content_type=args.payload_content_type, - algorithm=args.algorithm, bit_length=args.bit_length, - mode=args.mode, expiration=args.expiration) + if args.type == 'certificate': + request_data = None + if args.request_file: + try: + request_data = file(args.request_file).read() + except IOError: + raise ValueError( + 'Couldn\'t read request file %s.' % args.request_file) + + entity = self.app.client.orders.create( + name=args.name, type=args.type, subject_dn=args.subject_dn, + request_type=args.request_type, + source_container_ref=args.source_container_ref, + ca_id=args.ca_id, profile=args.profile, + request_data=request_data) + else: + entity = self.app.client.orders.create( + name=args.name, type=args.type, + payload_content_type=args.payload_content_type, + algorithm=args.algorithm, bit_length=args.bit_length, + mode=args.mode, expiration=args.expiration) entity.submit() return entity._get_formatted_entity() diff --git a/barbicanclient/orders.py b/barbicanclient/orders.py index 59ae028..360cbc1 100644 --- a/barbicanclient/orders.py +++ b/barbicanclient/orders.py @@ -85,6 +85,31 @@ class AsymmetricOrderFormatter(formatter.EntityFormatter): return data +class CertificateOrderFormatter(formatter.EntityFormatter): + + columns = ("Order href", + "Type", + "Container href", + "Secret href", + "Created", + "Status", + "Error code", + "Error message" + ) + + def _get_formatted_data(self): + data = (self.order_ref, + "Certificate", + self.container_ref, + "N/A", + self.created, + self.status, + self.error_status_code, + self.error_reason + ) + return data + + @six.add_metaclass(abc.ABCMeta) class Order(object): """ @@ -308,6 +333,38 @@ class AsymmetricOrder(Order, AsymmetricOrderFormatter): return 'AsymmetricOrder(order_ref={0})'.format(self.order_ref) +class CertificateOrder(Order, CertificateOrderFormatter): + _type = 'certificate' + + def __init__(self, api, name=None, + status=None, created=None, updated=None, order_ref=None, + container_ref=None, error_status_code=None, error_reason=None, + sub_status=None, sub_status_message=None, creator_id=None, + request_type=None, subject_dn=None, + source_container_ref=None, ca_id=None, profile=None, + request_data=None): + super(CertificateOrder, self).__init__( + api, self._type, status=status, created=created, updated=updated, + meta={ + 'name': name, + 'request_type': request_type, + 'subject_dn': subject_dn, + 'container_ref': source_container_ref, + 'ca_id': ca_id, + 'profile': profile, + 'request_data': request_data + }, order_ref=order_ref, error_status_code=error_status_code, + error_reason=error_reason) + self._container_ref = container_ref + + @property + def container_ref(self): + return self._container_ref + + def __repr__(self): + return 'CertificateOrder(order_ref={0})'.format(self.order_ref) + + class OrderManager(base.BaseEntityManager): """ Entity Manager for Order entitites @@ -315,7 +372,8 @@ class OrderManager(base.BaseEntityManager): _order_type_to_class_map = { 'key': KeyOrder, - 'asymmetric': AsymmetricOrder + 'asymmetric': AsymmetricOrder, + 'certificate': CertificateOrder } def __init__(self, api): @@ -345,12 +403,15 @@ class OrderManager(base.BaseEntityManager): resp_type = response.pop('type').lower() order_type = self._order_type_to_class_map.get(resp_type) + if (resp_type == 'certificate' and + 'container_ref' in response.get('meta', ())): + response['source_container_ref'] = response['meta'].pop( + 'container_ref') + response.update(response.pop('meta')) - if order_type is KeyOrder: - return KeyOrder(self._api, **response) - elif order_type is AsymmetricOrder: - return AsymmetricOrder(self._api, **response) + if order_type is not None: + return order_type(self._api, **response) else: raise TypeError('Unknown Order type "{0}"'.format(order_type)) @@ -412,6 +473,34 @@ class OrderManager(base.BaseEntityManager): payload_content_type=payload_content_type, expiration=expiration) + def create_certificate(self, name=None, request_type=None, subject_dn=None, + source_container_ref=None, ca_id=None, + profile=None, request_data=None): + """ + Factory method for `CertificateOrder` objects + + `CertificateOrder` objects returned by this method have not yet been + submitted to the Barbican service. + + :param name: A friendly name for the container to be created + :param request_type: The type of the certificate request + :param subject_dn: A subject for the certificate + :param source_container_ref: A container with a public/private key pair + to use as source for stored-key requests + :param ca_id: The identifier of the CA to use + :param profile: The profile of certificate to use + :param request_data: The CSR content + :returns: CertificateOrder + :rtype: :class:`barbicanclient.orders.CertificateOrder` + """ + return CertificateOrder(api=self._api, name=name, + request_type=request_type, + subject_dn=subject_dn, + source_container_ref=source_container_ref, + ca_id=ca_id, + profile=profile, + request_data=request_data) + def delete(self, order_ref): """ Delete an Order from Barbican diff --git a/barbicanclient/tests/test_orders.py b/barbicanclient/tests/test_orders.py index 34e1043..6cabea0 100644 --- a/barbicanclient/tests/test_orders.py +++ b/barbicanclient/tests/test_orders.py @@ -237,4 +237,89 @@ class WhenTestingOrderManager(OrdersTestCase): def test_should_get_total(self): self.responses.get(self.entity_base, json={'total': 1}) total = self.manager.total() - self.assertEqual(total, 1) + + +class WhenTestingCertificateOrders(test_client.BaseEntityResource): + def setUp(self): + self._setUp('orders', entity_id='d0460cc4-2876-4493-b7de-fc5c812883cc') + + self.container_ref = ( + self.endpoint + '/containers/a2292306-6da0-4f60-bd8a-84fc8d692716') + self.source_container_ref = ( + self.endpoint + '/containers/c6f20480-c1e5-442b-94a0-cb3b5e0cf179') + + self.cert_order_data = """{{ + "status": "ACTIVE", + "container_ref": "{0}", + "updated": "2014-10-21T17:15:50.871596", + "meta": {{ + "name": "secretname", + "subject_dn": "cn=server.example.com,o=example.com", + "request_type": "stored-key", + "container_ref": "{1}" + }}, + "created": "2014-10-21T17:15:50.824202", + "type": "certificate", + "order_ref": "{2}" + }}""".format(self.container_ref, self.source_container_ref, + self.entity_href) + + self.manager = self.client.orders + + def _get_order_args(self, order_data): + order_args = json.loads(order_data) + order_args.update(order_args.pop('meta')) + order_args.pop('type') + return order_args + + def test_get(self): + self.responses.get(self.entity_href, text=self.cert_order_data) + + order = self.manager.get(order_ref=self.entity_href) + self.assertIsInstance(order, orders.CertificateOrder) + self.assertEqual(self.entity_href, order.order_ref) + + # Verify the correct URL was used to make the call. + self.assertEqual(self.entity_href, self.responses.last_request.url) + + def test_repr(self): + order_args = self._get_order_args(self.cert_order_data) + order_obj = orders.CertificateOrder(api=None, **order_args) + self.assertIn('order_ref=' + self.entity_href, repr(order_obj)) + + def test_constructor(self): + data = {'order_ref': self.entity_href} + self.responses.post(self.entity_base + '/', json=data) + + order = self.manager.create_certificate( + name='name', + subject_dn='cn=server.example.com,o=example.com', + request_type='stored-key', + source_container_ref=self.source_container_ref + ) + order_href = order.submit() + + self.assertEqual(self.entity_href, order_href) + + # Verify the correct URL was used to make the call. + self.assertEqual(self.entity_base + '/', + self.responses.last_request.url) + + # Verify that correct information was sent in the call. + order_req = json.loads(self.responses.last_request.text) + self.assertEqual('name', order_req['meta']['name']) + self.assertEqual('cn=server.example.com,o=example.com', + order_req['meta']['subject_dn']) + self.assertEqual('stored-key', + order_req['meta']['request_type']) + self.assertEqual(self.source_container_ref, + order_req['meta']['container_ref']) + + def test_list(self): + data = {"orders": [json.loads(self.cert_order_data) for _ in range(3)]} + self.responses.get(self.entity_base, json=data) + + orders_list = self.manager.list(limit=10, offset=5) + self.assertEqual(len(orders_list), 3) + self.assertIsInstance(orders_list[0], orders.CertificateOrder) + self.assertEqual(self.entity_href, orders_list[0].order_ref) |