diff --git a/barbicanclient/__init__.py b/barbicanclient/__init__.py index 5498f3e0..61b2154b 100644 --- a/barbicanclient/__init__.py +++ b/barbicanclient/__init__.py @@ -1 +1 @@ -"""Barbican Client Library Binding""" \ No newline at end of file +"""Barbican Client Library Binding""" diff --git a/barbicanclient/client.py b/barbicanclient/client.py index d30993d7..b42d536a 100644 --- a/barbicanclient/client.py +++ b/barbicanclient/client.py @@ -11,7 +11,6 @@ from barbicanclient.common import auth from barbicanclient.openstack.common import log from barbicanclient.common.exceptions import ClientException from barbicanclient.openstack.common.gettextutils import _ -from openstack.common.timeutils import parse_isotime from urlparse import urljoin @@ -95,8 +94,8 @@ class Connection(object): self._session = requests.Session() - #headers = {"Client-Id": self._client_id} - #self._session.headers.update(headers) + # headers = {"Client-Id": self._client_id} + # self._session.headers.update(headers) self._session.verify = True if token: @@ -171,9 +170,10 @@ class Connection(object): return secrets, prev_ref, next_ref def create_secret(self, - mime_type, - plain_text=None, name=None, + payload=None, + payload_content_type=None, + payload_content_encoding=None, algorithm=None, bit_length=None, cypher_type=None, @@ -181,21 +181,24 @@ class Connection(object): """ Creates and returns a Secret object with all of its metadata filled in. - :param mime_type: The MIME type of the secret - :param plain_text: The unencrypted secret :param name: A friendly name for the secret + :param payload: The unencrypted secret + :param payload_content_type: The format/type of the secret + :param payload_content_encoding: The encoding of the secret :param algorithm: The algorithm the secret is used with :param bit_length: The bit length of the secret :param cypher_type: The cypher type (e.g. block cipher mode) :param expiration: The expiration time of the secret in ISO 8601 format """ - LOG.debug(_("Creating secret of mime_type {0}").format(mime_type)) + LOG.debug(_("Creating secret of payload content type {0}").format( + payload_content_type)) href = "{0}/{1}".format(self._tenant, self.SECRETS_PATH) LOG.debug(_("href: {0}").format(href)) secret_dict = {} - secret_dict['mime_type'] = mime_type - secret_dict['plain_text'] = plain_text secret_dict['name'] = name + secret_dict['payload'] = payload + secret_dict['payload_content_type'] = payload_content_type + secret_dict['payload_content_encoding'] = payload_content_encoding secret_dict['algorithm'] = algorithm secret_dict['cypher_type'] = cypher_type secret_dict['bit_length'] = bit_length @@ -249,25 +252,25 @@ class Connection(object): LOG.debug(_("Response - headers: {0}\nbody: {1}").format(hdrs, body)) return Secret(self._conn, body) - def get_raw_secret_by_id(self, secret_id, mime_type): + def get_raw_secret_by_id(self, secret_id, payload_content_type): """ Returns the raw secret :param secret_id: The UUID of the secret - :param mime_type: The MIME type of the secret + :param payload_content_type: The data type of the secret """ LOG.debug(_("Getting raw secret - Secret ID: {0}").format(secret_id)) href = "{0}/{1}/{2}".format(self._tenant, self.SECRETS_PATH, secret_id) - return self.get_raw_secret(href, mime_type) + return self.get_raw_secret(href, payload_content_type) - def get_raw_secret(self, href, mime_type): + def get_raw_secret(self, href, payload_content_type): """ Returns the raw secret :param href: The reference to the secret - :param mime_type: The MIME type of the secret + :param payload_content_type: The data type of the secret """ - hdrs = {"Accept": mime_type} + hdrs = {"Accept": payload_content_type} hdrs, body = self._perform_http(href=href, method='GET', headers=hdrs, parse_json=False) LOG.debug(_("Response - headers: {0}\nbody: {1}").format(hdrs, body)) @@ -317,29 +320,32 @@ class Connection(object): return orders, prev_ref, next_ref def create_order(self, - mime_type, name=None, - algorithm=None, - bit_length=None, - cypher_type=None): + payload_content_type='application/octet-stream', + algorithm='aes', + bit_length=256, + cypher_type='cbc', + expiration=None): """ Creates and returns an Order object with all of its metadata filled in. - :param mime_type: The MIME type of the secret :param name: A friendly name for the secret :param algorithm: The algorithm the secret is used with :param bit_length: The bit length of the secret :param cypher_type: The cypher type (e.g. block cipher mode) + :param expiration: The expiration time of the secret in ISO 8601 format """ - LOG.debug(_("Creating order of mime_type {0}").format(mime_type)) + LOG.debug(_("Creating order")) href = "{0}/{1}".format(self._tenant, self.ORDERS_PATH) LOG.debug("href: {0}".format(href)) order_dict = {'secret': {}} order_dict['secret']['name'] = name - order_dict['secret']['mime_type'] = mime_type + order_dict['secret'][ + 'payload_content_type'] = payload_content_type order_dict['secret']['algorithm'] = algorithm order_dict['secret']['bit_length'] = bit_length order_dict['secret']['cypher_type'] = cypher_type + order_dict['secret']['expiration'] = expiration self._remove_empty_keys(order_dict['secret']) LOG.debug(_("Request body: {0}").format(order_dict['secret'])) hdrs, body = self._perform_http(href=href, diff --git a/barbicanclient/common/auth.py b/barbicanclient/common/auth.py index ab2a979c..891f9d63 100644 --- a/barbicanclient/common/auth.py +++ b/barbicanclient/common/auth.py @@ -64,7 +64,7 @@ def authenticate(auth_url, user, key, tenant, **kwargs): filter_value=region, service_type=service_type, endpoint_type=endpoint_type) - except exceptions.EndpointNotFound as ex: + except exceptions.EndpointNotFound: raise ClientException('Endpoint not found in service catalog') return endpoint, _ksclient.auth_token diff --git a/barbicanclient/common/config.py b/barbicanclient/common/config.py index e5d9d004..865b7482 100644 --- a/barbicanclient/common/config.py +++ b/barbicanclient/common/config.py @@ -23,6 +23,7 @@ import logging.handlers import os import sys +from barbicanclient.openstack.common.gettextutils import _ from barbicanclient.version import __version__ from oslo.config import cfg diff --git a/barbicanclient/common/utils.py b/barbicanclient/common/utils.py index 843e04fe..55b1a0df 100644 --- a/barbicanclient/common/utils.py +++ b/barbicanclient/common/utils.py @@ -7,4 +7,4 @@ def proc_template(template, **kwargs): dictionary args and returning the strings. """ return template.format(**dict([(k, urllib.quote(v)) - for k, v in kwargs.items()])) \ No newline at end of file + for k, v in kwargs.items()])) diff --git a/barbicanclient/keep.py b/barbicanclient/keep.py index fa8c2430..b939aef4 100644 --- a/barbicanclient/keep.py +++ b/barbicanclient/keep.py @@ -46,24 +46,34 @@ class Keep: def add_create_args(self): create_parser = self.subparsers.add_parser('create', help='Create a ' 'secret or an order') - create_parser.add_argument('--mime_type', '-m', default='text/plain', - help='the MIME type of the raw secret (defa' - 'ult: %(default)s)') - create_parser.add_argument('--name', '-n', help='a human-friendly name' - ' used only for reference') - create_parser.add_argument('--algorithm', '-a', help='the algorithm us' - 'ed only for reference') + create_parser.add_argument('--name', '-n', + help='a human-friendly name') + create_parser.add_argument('--algorithm', '-a', default='aes', help='t' + 'he algorithm; used only for reference (def' + 'ault: %(default)s)') create_parser.add_argument('--bit_length', '-b', default=256, - help='the bit length of the secret used ' + help='the bit length of the secret; used ' 'only for reference (default: %(default)s)', type=int) - create_parser.add_argument('--cypher_type', '-c', help='the cypher typ' - 'e used only for reference') - create_parser.add_argument('--plain_text', '-p', help='the unencrypted' - ' secret (only used for secrets)') + create_parser.add_argument('--cypher_type', '-c', default="cbc", + help='the cypher type; used only for refere' + 'nce (default: %(default)s)') + create_parser.add_argument('--payload', '-p', help='the unencrypted' + ' secret; if provided, you must also provid' + 'e a payload_content_type (only used for se' + 'crets)') + create_parser.add_argument('--payload_content_type', '-t', + help='the type/format of the provided ' + 'secret data; "text/plain" is assumed to be' + ' UTF-8; required when --payload is su' + 'pplied and when creating orders') + create_parser.add_argument('--payload_content_encoding', '-d', + help='required if --payload_content_type is' + ' "application/octet-stream" (only used for' + ' secrets)') + create_parser.add_argument('--expiration', '-e', help='the expiration ' - 'time for the secret in ISO 8601 format ' - '(only used for secrets)') + 'time for the secret in ISO 8601 format') create_parser.set_defaults(func=self.create) def add_delete_args(self): @@ -81,10 +91,12 @@ class Keep: get_parser.add_argument('UUID', help='the universally unique identi' 'fier of the the secret or order') get_parser.add_argument('--raw', '-r', help='if specified, gets the ra' - 'w secret of type specified with --mime_type (' - 'only used for secrets)', action='store_true') - get_parser.add_argument('--mime_type', '-m', default='text/plain', - help='the MIME type of the raw secret (defa' + 'w secret of type specified with --payload_con' + 'tent_type (only used for secrets)', + action='store_true') + get_parser.add_argument('--payload_content_type', '-t', + default='text/plain', + help='the content type of the raw secret (defa' 'ult: %(default)s; only used for secrets)') get_parser.set_defaults(func=self.get) @@ -105,20 +117,22 @@ class Keep: def create(self, args): if args.type == 'secret': - secret = self.conn.create_secret(args.mime_type, - args.plain_text, - args.name, + secret = self.conn.create_secret(args.name, + args.payload, + args.payload_content_type, + args.payload_content_encoding, args.algorithm, args.bit_length, args.cypher_type, args.expiration) print secret else: - order = self.conn.create_order(args.mime_type, - args.name, + order = self.conn.create_order(args.name, + args.payload_content_type, args.algorithm, args.bit_length, - args.cypher_type) + args.cypher_type, + args.expiration) print order def delete(self, args): @@ -130,7 +144,8 @@ class Keep: def get(self, args): if args.type == 'secret': if args.raw: - print self.conn.get_raw_secret_by_id(args.UUID, args.mime_type) + print self.conn.get_raw_secret_by_id(args.UUID, + args.payload_content_type) else: print self.conn.get_secret_by_id(args.UUID) else: diff --git a/barbicanclient/orders.py b/barbicanclient/orders.py index 3345e458..c1171845 100644 --- a/barbicanclient/orders.py +++ b/barbicanclient/orders.py @@ -10,11 +10,12 @@ class Order(object): connection object for subtasks. """ self.connection = connection - self.status = order_dict.get('status') - self.secret = order_dict.get('secret') + self.secret = order_dict['secret'] + self.order_ref = order_dict['order_ref'] + self.created = parse_isotime(order_dict['created']) self.secret_ref = order_dict.get('secret_ref') - self.order_ref = order_dict.get('order_ref') - self.created = parse_isotime(order_dict.get('created')) + self.status = order_dict.get('status') + if order_dict.get('updated') is not None: self.updated = parse_isotime(order_dict['updated']) else: diff --git a/barbicanclient/secrets.py b/barbicanclient/secrets.py index 53e69736..d5ad4724 100644 --- a/barbicanclient/secrets.py +++ b/barbicanclient/secrets.py @@ -3,24 +3,29 @@ from openstack.common.timeutils import parse_isotime class Secret(object): + """ A secret is any data the user has stored in the key management system. """ + def __init__(self, connection, secret_dict): """ Builds a secret object from a json representation. Includes the connection object for subtasks. """ self.connection = connection - self.secret_ref = secret_dict['secret_ref'] + self.secret_ref = secret_dict.get('secret_ref') self.created = parse_isotime(secret_dict.get('created')) self.status = secret_dict.get('status') self.algorithm = secret_dict.get('algorithm') self.bit_length = secret_dict.get('bit_length') - self.mime_type = secret_dict.get('mime_type') - self.name = secret_dict.get('name') + self.payload_content_type = secret_dict.get('payload_content_type') + self.payload_content_encoding = secret_dict.get( + 'payload_content_encoding') + self.cypher_type = secret_dict.get('cypher_type') + self.name = secret_dict.get('name') if secret_dict.get('expiration') is not None: self.expiration = parse_isotime(secret_dict['expiration']) @@ -43,12 +48,15 @@ class Secret(object): " reference: {1}\n" " name: {2}\n" " created: {3}\n" - " MIME type: {4}\n" - " status: {5}\n" - " bit length: {6}\n" - " algorithm: {7}\n" - " cypher type: {8}\n" + " status: {4}\n" + " payload content type: {5}\n" + " payload content encoding: {6}\n" + " bit length: {7}\n" + " algorithm: {8}\n" + " cypher type: {9}\n" + " expiration: {10}\n" .format(self.id, self.secret_ref, self.name, self.created, - self.mime_type, self.status, self.bit_length, - self.algorithm, self.cypher_type) + self.status, self.payload_content_type, + self.payload_content_encoding, self.bit_length, + self.algorithm, self.cypher_type, self.expiration) ) diff --git a/barbicanclient/version.py b/barbicanclient/version.py index 5307f23e..63159c1b 100644 --- a/barbicanclient/version.py +++ b/barbicanclient/version.py @@ -17,5 +17,5 @@ Cloudkeep's Barbican Client version """ -__version__ = '0.2.1dev' +__version__ = '0.3.0' __version_info__ = tuple(__version__.split('.')) diff --git a/clientrc b/clientrc index 023adfcb..2fd67215 100644 --- a/clientrc +++ b/clientrc @@ -2,5 +2,5 @@ export OS_TENANT_NAME=demo export OS_USERNAME=demo export OS_PASSWORD=password export OS_AUTH_URL="http://keystone-int.cloudkeep.io:5000/v2.0/" -export BARBICAN_ENDPOINT="http://api-01-int.cloudkeep.io:9311/v1/" +export BARBICAN_ENDPOINT="http://localhost:9311/v1/" export AUTH_TOKEN='' diff --git a/tests/client_test.py b/tests/client_test.py index 48b35197..fcc24e50 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -104,10 +104,9 @@ class WhenTestingConnection(unittest.TestCase): endpoint=self.endpoint) def test_should_create_secret(self): - body = {'status': 'ACTIVE', - 'content_types': {'default': 'text/plain'}, + body = {'status': "ACTIVE", 'updated': '2013-06-07T16:13:38.889857', - 'cypher_type': 'CDC', + 'cypher_type': 'cbc', 'name': 'test_secret', 'algorithm': 'aes', 'created': '2013-06-07T16:13:38.889851', @@ -115,19 +114,20 @@ class WhenTestingConnection(unittest.TestCase): 'b5e-3738-408e-aaba-05a7177cade5', 'expiration': '2015-06-07T16:13:38.889851', 'bit_length': 256, - 'mime_type': 'text/plain' + 'payload_content_type': 'text/plain' } secret = client.Secret(self.connection, body) self.request.return_value.content = json.dumps(body) - created = self.connection.create_secret('text/plain', - 'Test secret', - name='test_secret', + created = self.connection.create_secret(name='test_secret', + payload='Test secret', algorithm='aes', bit_length=256, - cypher_type='CDC', + cypher_type='cbc', expiration='2015-06-07T16:13' - ':38.889851') + ':38.889851', + payload_content_type= + 'text/plain') self.assertTrue(self._are_equivalent(secret, created)) def test_should_create_order(self): @@ -137,12 +137,13 @@ class WhenTestingConnection(unittest.TestCase): "updated": "2013-06-07T19:00:37.338386", "created": "2013-06-07T19:00:37.298704", "secret": { - "cypher_type": "CDC", - "name": "test_secret", - "algorithm": "aes", - "expiration": "2015-06-07T19:00:37.298704", - "bit_length": 256, - "mime_type": "text/plain" + 'cypher_type': 'cbc', + 'name': 'test_secret', + 'algorithm': 'aes', + 'created': '2013-06-07T16:13:38.889851', + 'expiration': '2015-06-07T16:13:38.889851', + 'bit_length': 256, + 'payload_content_type': 'application/octet-stream' }, "order_ref": "http://localhost:9311/v1/12345/orders/003f2b91-" "2f53-4c0a-a0f3-33796671efc3" @@ -150,11 +151,11 @@ class WhenTestingConnection(unittest.TestCase): order = client.Order(self.connection, body) self.request.return_value.content = json.dumps(body) - created = self.connection.create_order('text/plain', - name='test_secret', - bit_length=256, + created = self.connection.create_order(name='test_secret', + payload_content_type='application/octet-stream', algorithm='aes', - cypher_type='CDC') + bit_length=256, + cypher_type='cbc') self.assertTrue(self._are_equivalent(order, created)) def test_list_no_secrets(self):