Repository URL to install this package:
Version:
6.0.1.dev7 ▾
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2013 TrilioData, Inc.
# All Rights Reserved.
"""
Handles all requests relating to keymanager + barbican.
"""
import copy
import sys
import json
import requests
from functools import wraps
import binascii
from oslo_config import cfg
from barbicanclient import client as barbican_client
from barbicanclient import exceptions as barbican_exception
from keystoneclient import exceptions as ks_exceptions
from workloadmgr.db import base
from workloadmgr import workloads as workloadAPI
from workloadmgr.vault import vault
from workloadmgr.db.workloadmgrdb import WorkloadMgrDB
from workloadmgr import exception
from workloadmgr.common import context as wlm_context
from workloadmgr.common.clients import client_plugin
from workloadmgr.openstack.common import log as logging
from workloadmgr.common import clients
# TODO: Try using common params from config file.
barbican_opts = [
cfg.StrOpt('barbican_catalog_info',
default='key-manager:barbican:publicURL',
help='Info to match when looking for cinder in the service '
'catalog. Format is : separated values of the form: '
'<service_type>:<service_name>:<endpoint_type>'),
cfg.StrOpt('barbican_production_endpoint_template',
default='http://localhost:9311/v1/%(project_id)s', # None,
help='Override service catalog lookup with template for barbican '
'endpoint e.g. http://localhost:9311/v1/%(project_id)s'),
cfg.StrOpt('os_region_name',
default=None,
help='region name of this node'),
cfg.IntOpt('barbican_http_retries',
default=3,
help='Number of barbicanclient retries on failed http calls'),
cfg.BoolOpt('barbican_api_insecure',
default=False,
help='Allow to perform insecure SSL requests to barbican'),
cfg.BoolOpt('barbican_cross_az_attach',
default=True,
help='Allow attach between instance and volume in different '
'availability zones.'),
]
CONF = cfg.CONF
CONF.register_opts(barbican_opts)
LOG = logging.getLogger(__name__)
def barbicanclient(context, refresh_token=False):
if hasattr(context, 'user_domain_id'):
if context.user_domain_id is None:
user_domain_id = 'default'
else:
user_domain_id = context.user_domain_id
elif hasattr(context, 'user_domain'):
if context.user_domain is None:
user_domain_id = 'default'
else:
user_domain_id = context.user_domain
else:
user_domain_id = 'default'
workload_api = workloadAPI.API()
trust = workload_api.trust_list(context, get_hidden=True, is_cloud_admin=False)
trust_details = None
if trust:
trust_details = workload_api.trust_show(context,trust[0].name)
if not trust_details:
trust = workload_api.trust_create(context, vault.CONF.trustee_role)
if len(trust):
trust_id = trust[0].value
if refresh_token:
context = wlm_context.RequestContext(
username=CONF.keystone_authtoken.admin_user,
password=CONF.keystone_authtoken.admin_password,
trust_id=trust_id,
tenant_id=context.project_id,
trustor_user_id=context.user_id,
user_domain_id=CONF.triliovault_user_domain_id,
is_admin=False)
else:
context = wlm_context.RequestContext(
trustor_user_id=context.user_id,
project_id=context.project_id,
auth_token=context.auth_token,
trust_id=trust_id,
user_domain_id=user_domain_id,
is_admin=False)
clients.initialise()
client_plugin = clients.Clients(context)
barbicanclient = client_plugin.client("barbican")
barbicanclient.client_plugin = barbicanclient
return barbicanclient
class BarbicanRestClient:
"""
REST Client Implementation of Barbican.
"""
secret_uri = '/v1/secrets/'
def __init__(self, context, auth, management_url):
self.context = context
self.auth_token = auth.auth_token
self.management_url = barbicanclient(context[1]).client.management_url + \
BarbicanRestClient.secret_uri
self.headers = self.to_dict(self.auth_token)
self.verify = CONF.clients.get('cafile', False)
def to_dict(self, auth_keystone_token):
headers = {
"X-Auth-Token": auth_keystone_token,
"Content-Type": "application/json; charset=utf-8"
}
return headers
def get(self, api, retry=CONF.clients.get('client_retry_limit', 3)):
res = None
try:
while retry:
res = requests.get(
self.management_url + api,
headers=self.headers,
verify=self.verify)
if 200 == res.status_code:
break
retry -= 1
return res.text
except Exception as ex:
LOG.exception(ex)
raise ex
def post(self):
pass
def put(self, api, metadata, retry=CONF.clients.get('client_retry_limit', 3)):
res = None
while retry:
res = requests.put(
self.management_url + api,
headers=self.headers,
data=json.dumps(metadata),
verify=self.verify)
if 201 == res.status_code:
return True
retry -= 1
return False
def exception_handler(ignore_exception=False, refresh_token=True, http=False):
def exception_handler_decorator(func):
@wraps(func)
def func_wrapper(*args, **argv):
try:
try:
if not http:
client = barbicanclient(args[1])
argv.update({'client': client})
return func(*args, **argv)
else:
client = BarbicanRestClient(args, args[1], args[2])
argv.update({'client': client})
return func(*args, **argv)
except Exception as ex:
if ignore_exception is True:
LOG.exception(ex)
else:
raise ex
except barbican_exception.HTTPAuthError as autherror:
LOG.error(autherror)
raise autherror
except barbican_exception.HTTPClientError as clienterror:
LOG.error(clienterror)
raise clienterror
except ks_exceptions.EndpointNotFound as ex:
LOG.error(ex)
raise ex
except exception.MissingCredentialError as ex:
LOG.error(ex)
raise ex
except Exception as ex:
LOG.exception(ex)
return func_wrapper
return exception_handler_decorator
class API(base.Base):
"""API for interacting with the key manager."""
@exception_handler()
def get_payload_from_secret_href(self, context, secret_href, **kwargs):
client = kwargs['client']
secret_obj = client.secrets.get(secret_href)
res = secret_obj.payload
try:
ret = res.decode('utf-8') if isinstance(res, bytes) else res
except UnicodeDecodeError:
res = binascii.hexlify(res)
ret = res.decode('utf-8') if isinstance(res, bytes) else res
except:
raise
return ret
@exception_handler(http=True)
def get_secret_metadata(self, context, secret_href, **kwargs):
client = kwargs['client']
status = client.get(secret_href + '/metadata')
return status
@exception_handler(http=True)
def update_secret_metadata(self, context, secret_href, metadata, **kwargs):
client = kwargs['client']
status = client.put(secret_href + '/metadata', metadata)
if status:
return status
else:
raise Exception('Could not update metadata of secret.')
@exception_handler()
def create_secret(self, context, name=None, payload=None, algorithm=None, bit_length=None, mode=None,
secret_type=None, expiration=None):
client = kwargs['client']
return client.secrets.create()
@exception_handler()
def list_all_secret(self, context, limit=100, offset=0, name=None, algorithm=None, mode=None, **kwargs):
""" searches for all secrets for that user and project with limit and offset. """
list_secrets = []
client = kwargs['client']
while True:
res = client.secrets.list(limit=limit, offset=offset)
list_secrets += res
if len(res) < 100:
return list_secrets
offset += limit
@exception_handler()
def get_secret(self, context, secret_id=None, secret_href=None, **kwargs):
client = kwargs['client']
if not secret_href:
endpoint = client.client.get_endpoint()
secret_href = endpoint + 'secrets/%s' % (secret_id)
return client.secrets.get(secret_href)
@exception_handler()
def get_barbican_endpoint(self, context, **kwargs):
client = kwargs['client']
return client.client.get_endpoint()