Merge pull request #15 from Aghoreyshi/master

Update the client library and keep to comply with the MIME type revamp (merged on behalf of Doug!)
This commit is contained in:
Paul Kehrer
2013-08-16 13:30:38 -07:00
11 changed files with 118 additions and 86 deletions

View File

@@ -1 +1 @@
"""Barbican Client Library Binding"""
"""Barbican Client Library Binding"""

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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()]))
for k, v in kwargs.items()]))

View File

@@ -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:

View File

@@ -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:

View File

@@ -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)
)

View File

@@ -17,5 +17,5 @@
Cloudkeep's Barbican Client version
"""
__version__ = '0.2.1dev'
__version__ = '0.3.0'
__version_info__ = tuple(__version__.split('.'))

View File

@@ -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=''

View File

@@ -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):