"Fossies" - the Fresh Open Source Software Archive

Member "tacker-2.0.0/tacker/keymgr/barbican_key_manager.py" (16 Oct 2019, 10382 Bytes) of package /linux/misc/openstack/tacker-2.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "barbican_key_manager.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.9.0_vs_1.0.0.

    1 # Copyright (c) The Johns Hopkins University/Applied Physics Laboratory
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 """
   17 Key manager implementation for Barbican
   18 """
   19 from barbicanclient import client as barbican_client
   20 from barbicanclient import exceptions as barbican_exception
   21 from keystoneauth1 import identity
   22 from keystoneauth1 import session
   23 from oslo_log import log as logging
   24 
   25 from tacker._i18n import _
   26 from tacker.keymgr import exception
   27 from tacker.keymgr import key_manager
   28 
   29 
   30 LOG = logging.getLogger(__name__)
   31 
   32 
   33 class BarbicanKeyManager(key_manager.KeyManager):
   34     """Key Manager Interface that wraps the Barbican client API."""
   35 
   36     def __init__(self, auth_url):
   37         self._barbican_client = None
   38         self._base_url = None
   39         self._auth_url = auth_url
   40 
   41     def _get_barbican_client(self, context):
   42         """Creates a client to connect to the Barbican service.
   43 
   44         :param context: the user context for authentication
   45         :return: a Barbican Client object
   46         :raises Forbidden: if the context is empty
   47         :raises KeyManagerError: if context is missing tenant or tenant is
   48                                  None or error occurs while creating client
   49         """
   50 
   51         # Confirm context is provided, if not raise forbidden
   52         if not context:
   53             msg = _("User is not authorized to use key manager.")
   54             LOG.error(msg)
   55             raise exception.Forbidden(msg)
   56 
   57         if self._barbican_client and self._current_context == context:
   58             return self._barbican_client
   59 
   60         try:
   61             auth = self._get_keystone_auth(context)
   62             sess = session.Session(auth=auth)
   63 
   64             self._barbican_endpoint = self._get_barbican_endpoint(auth, sess)
   65             if self._barbican_endpoint[-1] != '/':
   66                 self._barbican_endpoint += '/'
   67             self._barbican_client = barbican_client.Client(
   68                 session=sess,
   69                 endpoint=self._barbican_endpoint)
   70             self._current_context = context
   71 
   72         except Exception as e:
   73             LOG.error("Error creating Barbican client: %s", e)
   74             raise exception.KeyManagerError(reason=e)
   75 
   76         self._base_url = self._create_base_url(auth,
   77                                                sess,
   78                                                self._barbican_endpoint)
   79 
   80         return self._barbican_client
   81 
   82     def _get_keystone_auth(self, context):
   83 
   84         if context.__class__.__name__ is 'KeystonePassword':
   85             return identity.Password(
   86                 auth_url=self._auth_url,
   87                 username=context.username,
   88                 password=context.password,
   89                 user_id=context.user_id,
   90                 user_domain_id=context.user_domain_id,
   91                 user_domain_name=context.user_domain_name,
   92                 trust_id=context.trust_id,
   93                 domain_id=context.domain_id,
   94                 domain_name=context.domain_name,
   95                 project_id=context.project_id,
   96                 project_name=context.project_name,
   97                 project_domain_id=context.project_domain_id,
   98                 project_domain_name=context.project_domain_name,
   99                 reauthenticate=context.reauthenticate)
  100         elif context.__class__.__name__ is 'KeystoneToken':
  101             return identity.Token(
  102                 auth_url=self._auth_url,
  103                 token=context.token,
  104                 trust_id=context.trust_id,
  105                 domain_id=context.domain_id,
  106                 domain_name=context.domain_name,
  107                 project_id=context.project_id,
  108                 project_name=context.project_name,
  109                 project_domain_id=context.project_domain_id,
  110                 project_domain_name=context.project_domain_name,
  111                 reauthenticate=context.reauthenticate)
  112         # this will be kept for oslo.context compatibility until
  113         # projects begin to use utils.credential_factory
  114         elif (context.__class__.__name__ is 'RequestContext' or
  115               context.__class__.__name__ is 'Context'):
  116             return identity.Token(
  117                 auth_url=self._auth_url,
  118                 token=context.auth_token,
  119                 project_id=context.tenant)
  120         else:
  121             msg = _("context must be of type KeystonePassword, "
  122                     "KeystoneToken, RequestContext, or Context, got type "
  123                     "%s") % context.__class__.__name__
  124             LOG.error(msg)
  125             raise exception.Forbidden(reason=msg)
  126 
  127     def _get_barbican_endpoint(self, auth, sess):
  128         service_parameters = {'service_type': 'key-manager',
  129                               'service_name': 'barbican',
  130                               'interface': 'internal'}
  131         return auth.get_endpoint(sess, **service_parameters)
  132 
  133     def _create_base_url(self, auth, sess, endpoint):
  134         discovery = auth.get_discovery(sess, url=endpoint)
  135         raw_data = discovery.raw_version_data()
  136         if len(raw_data) == 0:
  137             msg = _(
  138                 "Could not find discovery information for %s") % endpoint
  139             LOG.error(msg)
  140             raise exception.KeyManagerError(reason=msg)
  141         latest_version = raw_data[-1]
  142         api_version = latest_version.get('id')
  143         base_url = "%s%s/" % (endpoint, api_version)
  144         return base_url
  145 
  146     def store(self, context, secret, expiration=None):
  147         """Stores a secret with the key manager.
  148 
  149         :param context: contains information of the user and the environment
  150             for the request
  151         :param secret: a secret object with unencrypted payload.
  152             Known as "secret" to the barbicanclient api
  153         :param expiration: the expiration time of the secret in ISO 8601
  154             format
  155         :returns: the UUID of the stored object
  156         :raises KeyManagerError: if object store fails
  157         """
  158         barbican_client = self._get_barbican_client(context)
  159 
  160         try:
  161             secret = barbican_client.secrets.create(
  162                 payload=secret,
  163                 secret_type='opaque')
  164             secret.expiration = expiration
  165             secret_ref = secret.store()
  166             return self._retrieve_secret_uuid(secret_ref)
  167         except (barbican_exception.HTTPAuthError,
  168                 barbican_exception.HTTPClientError,
  169                 barbican_exception.HTTPServerError) as e:
  170             LOG.error("Error storing object: %s", e)
  171             raise exception.KeyManagerError(reason=e)
  172 
  173     def _create_secret_ref(self, object_id):
  174         """Creates the URL required for accessing a secret.
  175 
  176         :param object_id: the UUID of the key to copy
  177         :return: the URL of the requested secret
  178         """
  179         if not object_id:
  180             msg = _("Key ID is None")
  181             raise exception.KeyManagerError(reason=msg)
  182         return "%ssecrets/%s" % (self._base_url, object_id)
  183 
  184     def _retrieve_secret_uuid(self, secret_ref):
  185         """Retrieves the UUID of the secret from the secret_ref.
  186 
  187         :param secret_ref: the href of the secret
  188         :return: the UUID of the secret
  189         """
  190 
  191         # The secret_ref is assumed to be of a form similar to
  192         # http://host:9311/v1/secrets/d152fa13-2b41-42ca-a934-6c21566c0f40
  193         # with the UUID at the end. This command retrieves everything
  194         # after the last '/', which is the UUID.
  195         return secret_ref.rpartition('/')[2]
  196 
  197     def _is_secret_not_found_error(self, error):
  198         if (isinstance(error, barbican_exception.HTTPClientError) and
  199                 error.status_code == 404):
  200             return True
  201         else:
  202             return False
  203 
  204     def get(self, context, managed_object_id, metadata_only=False):
  205         """Retrieves the specified managed object.
  206 
  207         :param context: contains information of the user and the environment
  208                         for the request
  209         :param managed_object_id: the UUID of the object to retrieve
  210         :param metadata_only: whether secret data should be included
  211         :return: ManagedObject representation of the managed object
  212         :raises KeyManagerError: if object retrieval fails
  213         :raises ManagedObjectNotFoundError: if object not found
  214         """
  215         barbican_client = self._get_barbican_client(context)
  216 
  217         try:
  218             secret_ref = self._create_secret_ref(managed_object_id)
  219             return barbican_client.secrets.get(secret_ref)
  220         except (barbican_exception.HTTPAuthError,
  221                 barbican_exception.HTTPClientError,
  222                 barbican_exception.HTTPServerError) as e:
  223             LOG.error("Error retrieving object: %s", e)
  224             if self._is_secret_not_found_error(e):
  225                 raise exception.ManagedObjectNotFoundError(
  226                     uuid=managed_object_id)
  227             else:
  228                 raise exception.KeyManagerError(reason=e)
  229 
  230     def delete(self, context, managed_object_id):
  231         """Deletes the specified managed object.
  232 
  233         :param context: contains information of the user and the environment
  234                      for the request
  235         :param managed_object_id: the UUID of the object to delete
  236         :raises KeyManagerError: if object deletion fails
  237         :raises ManagedObjectNotFoundError: if the object could not be found
  238         """
  239         barbican_client = self._get_barbican_client(context)
  240 
  241         try:
  242             secret_ref = self._create_secret_ref(managed_object_id)
  243             barbican_client.secrets.delete(secret_ref)
  244         except (barbican_exception.HTTPAuthError,
  245                 barbican_exception.HTTPClientError,
  246                 barbican_exception.HTTPServerError) as e:
  247             LOG.error("Error deleting object: %s", e)
  248             if self._is_secret_not_found_error(e):
  249                 pass
  250             else:
  251                 raise exception.KeyManagerError(reason=e)