def load_body(req, resp=None, validator=None): """Helper function for loading an HTTP request body from JSON. This body is placed into into a Python dictionary. :param req: The HTTP request instance to load the body from. :param resp: The HTTP response instance. :param validator: The JSON validator to enforce. :return: A dict of values from the JSON request. """ try: body = req.body_file.read(CONF.max_allowed_request_size_in_bytes) req.body_file.seek(0) except IOError: LOG.exception(u._LE("Problem reading request JSON stream.")) pecan.abort(500, u._('Read Error')) try: # TODO(jwood): Investigate how to get UTF8 format via openstack # jsonutils: # parsed_body = json.loads(raw_json, 'utf-8') parsed_body = json.loads(body) strip_whitespace(parsed_body) except ValueError: LOG.exception(u._LE("Problem loading request JSON.")) pecan.abort(400, u._('Malformed JSON')) if validator: try: parsed_body = validator.validate(parsed_body) except exception.BarbicanHTTPException as e: LOG.exception(e.message) pecan.abort(e.status_code, e.client_message) return parsed_body
def process(self, *args, **kwargs): """A template method for all asynchronous tasks. This method should not be overridden by sub-classes. Rather the abstract methods below should be overridden. :param args: List of arguments passed in from the client. :param kwargs: Dict of arguments passed in from the client. :return: Returns :class:`FollowOnProcessingStatusDTO` if follow-on processing (such as retrying this or another task) is required, otherwise a None return indicates that no follow-on processing is required. """ name = self.get_name() result = None # Retrieve the target entity (such as an models.Order instance). try: entity = self.retrieve_entity(*args, **kwargs) except Exception: # Serious error! LOG.exception( u._LE("Could not retrieve information needed to " "process task '%s'."), name) raise # Process the target entity. try: result = self.handle_processing(entity, *args, **kwargs) except Exception as e_orig: LOG.exception( u._LE("Could not perform processing for " "task '%s'."), name) # Handle failure to process entity. try: status, message = api.generate_safe_exception_message( name, e_orig) self.handle_error(entity, status, message, e_orig, *args, **kwargs) except Exception: LOG.exception( u._LE("Problem handling an error for task '%s', " "raising original " "exception."), name) raise e_orig # Handle successful conclusion of processing. try: self.handle_success(entity, result, *args, **kwargs) except Exception: LOG.exception( u._LE("Could not process after successfully " "executing task '%s'."), name) raise return result
def process(self, *args, **kwargs): """A template method for all asynchronous tasks. This method should not be overridden by sub-classes. Rather the abstract methods below should be overridden. :param args: List of arguments passed in from the client. :param kwargs: Dict of arguments passed in from the client. :return: Returns :class:`FollowOnProcessingStatusDTO` if follow-on processing (such as retrying this or another task) is required, otherwise a None return indicates that no follow-on processing is required. """ name = self.get_name() result = None # Retrieve the target entity (such as an models.Order instance). try: entity = self.retrieve_entity(*args, **kwargs) except Exception as e: # Serious error! LOG.exception(u._LE("Could not retrieve information needed to " "process task '%s'."), name) raise e # Process the target entity. try: result = self.handle_processing(entity, *args, **kwargs) except Exception as e_orig: LOG.exception(u._LE("Could not perform processing for " "task '%s'."), name) # Handle failure to process entity. try: status, message = api.generate_safe_exception_message(name, e_orig) self.handle_error(entity, status, message, e_orig, *args, **kwargs) except Exception: LOG.exception(u._LE("Problem handling an error for task '%s', " "raising original " "exception."), name) raise e_orig # Handle successful conclusion of processing. try: self.handle_success(entity, result, *args, **kwargs) except Exception as e: LOG.exception(u._LE("Could not process after successfully " "executing task '%s'."), name) raise e return result
def create_from(self, entity, session=None): """Sub-class hook: create from entity.""" if not entity: msg = u._("Must supply non-None {entity_name}.").format( entity_name=self._do_entity_name()) raise exception.Invalid(msg) if entity.id: msg = u._( "Must supply {entity_name} with id=None (i.e. new entity)." ).format(entity_name=self._do_entity_name()) raise exception.Invalid(msg) LOG.debug("Begin create from...") start = time.time() # DEBUG # Validate the attributes before we go any further. From my # (unknown Glance developer) investigation, the @validates # decorator does not validate # on new records, only on existing records, which is, well, # idiotic. self._do_validate(entity.to_dict()) try: LOG.debug("Saving entity...") entity.save(session=session) except sqlalchemy.exc.IntegrityError: LOG.exception(u._LE('Problem saving entity for create')) _raise_entity_already_exists(self._do_entity_name()) LOG.debug('Elapsed repo ' 'create secret:%s', (time.time() - start)) # DEBUG return entity
def delete_project_entities(self, project_id, suppress_exception=False, session=None): """Deletes entities for a given project. :param project_id: id of barbican project entity :param suppress_exception: Pass True if want to suppress exception :param session: existing db session reference. If None, gets session. Sub-class should implement `_build_get_project_entities_query` function to delete related entities otherwise it would raise NotImplementedError on its usage. """ session = self.get_session(session) query = self._build_get_project_entities_query(project_id, session=session) try: # query cannot be None as related repo class is expected to # implement it otherwise error is raised in build query call for entity in query: # Its a soft delete so its more like entity update entity.delete(session=session) except sqlalchemy.exc.SQLAlchemyError: LOG.exception( u._LE('Problem finding project related entity to ' 'delete')) if not suppress_exception: raise exception.BarbicanException( u._('Error deleting project ' 'entities for ' 'project_id=%s'), project_id)
def get(self, entity_id, external_project_id=None, force_show_deleted=False, suppress_exception=False, session=None): """Get an entity or raise if it does not exist.""" session = self.get_session(session) try: query = self._do_build_get_query(entity_id, external_project_id, session) # filter out deleted entities if requested if not force_show_deleted: query = query.filter_by(deleted=False) entity = query.one() except sa_orm.exc.NoResultFound: LOG.exception(u._LE("Not found for %s"), entity_id) entity = None if not suppress_exception: _raise_entity_not_found(self._do_entity_name(), entity_id) return entity
def wrapper(*args, **kwargs): fn_name = getattr(fn, '__name__', '????') if not queue.is_server_side(): # Non-server mode directly invokes tasks. fn(*args, **kwargs) LOG.info(u._LI("Completed worker task: '%s'"), fn_name) else: # Manage session/transaction. try: fn(*args, **kwargs) repositories.commit() LOG.info(u._LI("Completed worker task: '%s'"), fn_name) except Exception: """NOTE: Wrapped functions must process with care! Exceptions that reach here will revert the entire transaction, including any updates made to entities such as setting error codes and error messages. """ LOG.exception( u._LE("Problem seen processing worker task: '%s'"), fn_name ) repositories.rollback() finally: repositories.clear()
def on_delete(self, external_project_id, **kwargs): data = api.load_body(pecan.request, validator=self.validator) LOG.debug(data) consumer = self.consumer_repo.get_by_values( self.container_id, data["name"], data["URL"], suppress_exception=True ) if not consumer: _consumer_not_found() LOG.debug("Found consumer: %s", consumer) try: self.consumer_repo.delete_entity_by_id(consumer.id, external_project_id) except exception.NotFound: LOG.exception(u._LE('Problem deleting consumer')) _consumer_not_found() ret_data = self._return_container_data( self.container_id, external_project_id ) LOG.info(u._LI('Deleted a consumer for project: %s'), external_project_id) return ret_data
def generate_symmetric_key(self, key_spec): """Generate a symmetric key. Creates KMIP attribute objects based on the given KeySpec to send to the server. :param key_spec: KeySpec with symmetric algorithm and bit_length :returns: dictionary holding key_id returned by server :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting symmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.SYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to the " "'generate_symmetric_key' method").format( algorithm=key_spec.alg ) ) algorithm = self._get_kmip_algorithm(key_spec.alg) try: with self.client: LOG.debug("Opened connection to KMIP client for secret " + "generation") uuid = self.client.create(algorithm, key_spec.bit_length) LOG.debug("SUCCESS: Symmetric key generated with " "uuid: %s", uuid) return {KMIPSecretStore.KEY_UUID: uuid} except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def generate_symmetric_key(self, key_spec): """Generate a symmetric key. Creates KMIP attribute objects based on the given KeySpec to send to the server. :param key_spec: KeySpec with symmetric algorithm and bit_length :returns: dictionary holding key_id returned by server :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting symmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.SYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to the " "'generate_symmetric_key' method").format( algorithm=key_spec.alg)) algorithm = self._get_kmip_algorithm(key_spec.alg) try: with self.client: LOG.debug("Opened connection to KMIP client for secret " + "generation") uuid = self.client.create(algorithm, key_spec.bit_length) LOG.debug("SUCCESS: Symmetric key generated with " "uuid: %s", uuid) return {KMIPSecretStore.KEY_UUID: uuid} except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def delete_secret(self, secret_metadata): """Deletes the secret whose metadata is included in the dictionary. Returns nothing if successful, raises an exception if an error occurs :param secret_metadata: Dictionary of key metadata, requires: {'key_uuid': <uuid of key>} :raises: SecretGeneralException """ LOG.debug("Starting secret deletion with KMIP plugin") uuid = str(secret_metadata[KMIPSecretStore.KEY_UUID]) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret deletion") result = self.client.destroy(uuid=uuid, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Key with uuid %s deleted", uuid) else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret deletion")
def _check_retry_tasks(self): """Periodically check to see if tasks need to be scheduled. :return: Return the number of seconds to wait before invoking this method again. """ total_tasks_processed = 0 try: total_tasks_processed = self._process_retry_tasks() except Exception: LOG.exception( u._LE("Problem seen processing scheduled retry tasks") ) # Return the next delay before this method is invoked again. check_again_in_seconds = _compute_next_periodic_interval() LOG.info( u._LI("Done processing '%(total)s' tasks, will check again in " "'%(next)s' seconds."), { 'total': total_tasks_processed, 'next': check_again_in_seconds } ) return check_again_in_seconds
def process_and_suppress_exceptions(self, *args, **kwargs): """Invokes the process() template method, suppressing all exceptions. TODO(john-wood-w) This method suppresses exceptions for flows that do not want to rollback database modifications in reaction to such exceptions, as this could also rollback the marking of the entity (eg. order) in the ERROR status via the handle_error() call below. For Liberty, we might want to consider a workflow manager instead of these process_xxxx() method as shown here: https://gist.github.com/jfwood/a8130265b0db3c793ec8 :param args: List of arguments passed in from the client. :param kwargs: Dict of arguments passed in from the client. :return: Returns :class:`FollowOnProcessingStatusDTO` if follow-on processing (such as retrying this or another task) is required, otherwise a None return indicates that no follow-on processing is required. """ try: return self.process(*args, **kwargs) except Exception: LOG.exception( u._LE( "Suppressing exception while trying to " "process task '%s'."), self.get_name())
def on_delete(self, external_project_id, **kwargs): data = api.load_body(pecan.request, validator=self.validator) LOG.debug('Start on_delete...%s', data) project = self.project_repo.find_by_external_project_id( external_project_id, suppress_exception=True) if not project: _consumer_not_found() consumer = self.consumer_repo.get_by_values(self.container_id, data["name"], data["URL"], suppress_exception=True) if not consumer: _consumer_not_found() LOG.debug("Found consumer: %s", consumer) container = self._get_container(self.container_id) owner_of_consumer = consumer.project_id == project.id owner_of_container = container.project.external_id \ == external_project_id if not owner_of_consumer and not owner_of_container: _consumer_ownership_mismatch() try: self.consumer_repo.delete_entity_by_id(consumer.id, external_project_id) except exception.NotFound: LOG.exception(u._LE('Problem deleting consumer')) _consumer_not_found() ret_data = self._return_container_data(self.container_id) LOG.info(u._LI('Deleted a consumer for project: %s'), external_project_id) return ret_data
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException(secret_dto.key_spec.alg) secret_type = secret_dto.type object_type, key_format_type = self._map_type_ss_to_kmip(secret_type) if object_type is None: raise KMIPSecretStoreError( u._("Secret object type {object_type} is " "not supported").format(object_type=object_type) ) secret = self._get_kmip_secret(secret_dto) try: with self.client: LOG.debug("Opened connection to KMIP client") uuid = self.client.register(secret) LOG.debug("SUCCESS: Key stored with uuid: %s", uuid) return {KMIPSecretStore.KEY_UUID: uuid} except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def _raise_secret_general_exception(self, result): msg = u._("Status: {status}, Reason: {reason}, " "Message: {message}").format(status=result.result_status, reason=result.result_reason, message=result.result_message) LOG.error(u._LE("ERROR from KMIP server: %s"), msg) raise ss.SecretGeneralException(msg)
def handle_error(self, order, status, message, exception, *args, **kwargs): order.status = models.States.ERROR order.error_status_code = status order.error_reason = message LOG.exception(u._LE("An error has occurred updating the order.")) self.repos.order_repo.save(order)
def instantiate_plugins(extension_manager, invoke_args=(), invoke_kwargs={}): """Attempt to create each plugin managed by a stevedore manager. While we could have let the stevedore 'extension_manager' create our plugins by passing 'invoke_on_load=True' to its initializer, its logic handles and suppresses any root cause exceptions emanating from the plugins' initializers. This function allows those exceptions to be exposed. :param extension_manager: A :class:`NamedExtensionManager` instance that has already processed the configured plugins, but has not yet created instances of these plugins. :param invoke_args: Arguments to pass to the new plugin instance. :param invoke_kwargs: Keyword arguments to pass to the new plugin instance. """ for ext in extension_manager.extensions: if not ext.obj: try: plugin_instance = ext.plugin(*invoke_args, **invoke_kwargs) except Exception: LOG.logger.disabled = False # Ensure not suppressing logs. LOG.exception( u._LE("Problem seen creating plugin: '%s'"), ext.name ) else: ext.obj = plugin_instance
def __init__(self, **kwargs): if kwargs: # Enforce that either all arguments are non-None or else all None. test_set = set(kwargs.values()) if None in test_set and len(test_set) > 1: raise NotImplementedError( u._LE('No support for mixing None ' 'and non-None repository ' 'instances.')) # Only set properties for specified repositories. self._set_repo('project_repo', ProjectRepo, kwargs) self._set_repo('project_secret_repo', ProjectSecretRepo, kwargs) self._set_repo('secret_repo', SecretRepo, kwargs) self._set_repo('datum_repo', EncryptedDatumRepo, kwargs) self._set_repo('kek_repo', KEKDatumRepo, kwargs) self._set_repo('secret_meta_repo', SecretStoreMetadatumRepo, kwargs) self._set_repo('order_repo', OrderRepo, kwargs) self._set_repo('order_plugin_meta_repo', OrderPluginMetadatumRepo, kwargs) self._set_repo('transport_key_repo', TransportKeyRepo, kwargs) self._set_repo('container_repo', ContainerRepo, kwargs) self._set_repo('container_secret_repo', ContainerSecretRepo, kwargs)
def wrapper(*args, **kwargs): fn_name = find_function_name(fn, if_no_name='???') if not queue.is_server_side(): # Non-server mode directly invokes tasks. fn(*args, **kwargs) LOG.info(u._LI("Completed worker task: '%s'"), fn_name) else: # Manage session/transaction. try: fn(*args, **kwargs) repositories.commit() LOG.info(u._LI("Completed worker task (post-commit): '%s'"), fn_name) except Exception: """NOTE: Wrapped functions must process with care! Exceptions that reach here will revert the entire transaction, including any updates made to entities such as setting error codes and error messages. """ LOG.exception( u._LE("Problem seen processing worker task: '%s'"), fn_name) repositories.rollback() finally: repositories.clear()
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) secret_type = secret_dto.type object_type, key_format_type = (self._map_type_ss_to_kmip(secret_type)) if object_type is None: raise KMIPSecretStoreError( u._('Secret object type {object_type} is ' 'not supported').format(object_type=object_type)) secret = self._get_kmip_secret(secret_dto) try: with self.client: LOG.debug("Opened connection to KMIP client") uuid = self.client.register(secret) LOG.debug("SUCCESS: Key stored with uuid: %s", uuid) return {KMIPSecretStore.KEY_UUID: uuid} except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def on_delete(self, external_project_id, **kwargs): try: self.order_repo.delete_entity_by_id( entity_id=self.order_id, external_project_id=external_project_id) except exception.NotFound: LOG.exception(u._LE('Problem deleting order')) _order_not_found()
def generate_symmetric_key(self, key_spec): """Generate a symmetric key. Creates KMIP attribute objects based on the given KeySpec to send to the server. :param key_spec: KeySpec with symmetric algorithm and bit_length :returns: dictionary holding key_id returned by server :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting symmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException( key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.SYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to the " "'generate_symmetric_key' method").format( algorithm=key_spec.alg)) object_type = enums.ObjectType.SYMMETRIC_KEY algorithm = self._create_cryptographic_algorithm_attribute( key_spec.alg) usage_mask = self._create_usage_mask_attribute(object_type) length = self._create_cryptographic_length_attribute( key_spec.bit_length) attribute_list = [algorithm, usage_mask, length] template_attribute = TemplateAttribute( attributes=attribute_list) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret " + "generation") result = self.client.create(object_type=object_type, template_attribute=template_attribute, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Symmetric key generated with " "uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret " + "generation")
def update_ca_info(self, cert_plugin): """Update the CA info for a particular plugin.""" plugin_name = utils.generate_fullname_for(cert_plugin) try: new_ca_infos = cert_plugin.get_ca_info() except Exception as e: # The plugin gave an invalid CA, log and return LOG.error(u._LE("ERROR getting CA from plugin: %s"), encodeutils.exception_to_unicode(e)) return old_cas, offset, limit, total = self.ca_repo.get_by_create_date( plugin_name=plugin_name, suppress_exception=True, show_expired=True) if old_cas: for old_ca in old_cas: plugin_ca_id = old_ca.plugin_ca_id if plugin_ca_id not in new_ca_infos.keys(): # remove CAs that no longer exist self._delete_ca(old_ca) else: # update those that still exist self.ca_repo.update_entity( old_ca, new_ca_infos[plugin_ca_id]) old_ids = set([ca.plugin_ca_id for ca in old_cas]) else: old_ids = set() new_ids = set(new_ca_infos.keys()) # add new CAs add_ids = new_ids - old_ids for add_id in add_ids: try: self._add_ca(plugin_name, add_id, new_ca_infos[add_id]) except Exception as e: # The plugin gave an invalid CA, log and continue LOG.error(u._LE("ERROR adding CA from plugin: %s"), encodeutils.exception_to_unicode(e))
def update_ca_info(self, cert_plugin): """Update the CA info for a particular plugin.""" plugin_name = utils.generate_fullname_for(cert_plugin) try: new_ca_infos = cert_plugin.get_ca_info() except Exception as e: # The plugin gave an invalid CA, log and return LOG.error(u._LE("ERROR getting CA from plugin: %s"), encodeutils.exception_to_unicode(e)) return old_cas, offset, limit, total = self.ca_repo.get_by_create_date( plugin_name=plugin_name, suppress_exception=True, show_expired=True) if old_cas: for old_ca in old_cas: plugin_ca_id = old_ca.plugin_ca_id if plugin_ca_id not in new_ca_infos.keys(): # remove CAs that no longer exist self._delete_ca(old_ca) else: # update those that still exist self.ca_repo.update_entity(old_ca, new_ca_infos[plugin_ca_id]) old_ids = set([ca.plugin_ca_id for ca in old_cas]) else: old_ids = set() new_ids = set(new_ca_infos.keys()) # add new CAs add_ids = new_ids - old_ids for add_id in add_ids: try: self._add_ca(plugin_name, add_id, new_ca_infos[add_id]) except Exception as e: # The plugin gave an invalid CA, log and continue LOG.error(u._LE("ERROR adding CA from plugin: %s"), encodeutils.exception_to_unicode(e))
def _raise_secret_general_exception(self, result): msg = u._( "Status: {status}, Reason: {reason}, " "Message: {message}" ).format( status=result.result_status, reason=result.result_reason, message=result.result_message ) LOG.error(u._LE("ERROR from KMIP server: %s"), msg) raise ss.SecretGeneralException(msg)
def on_delete(self, external_project_id, **kwargs): LOG.debug("== Deleting transport key ===") try: self.repo.delete_entity_by_id( entity_id=self.transport_key_id, external_project_id=external_project_id) # TODO(alee) response should be 204 on success # pecan.response.status = 204 except exception.NotFound: LOG.exception(u._LE('Problem deleting transport_key')) _transport_key_not_found()
def generate_symmetric_key(self, key_spec): """Generate a symmetric key. Creates KMIP attribute objects based on the given KeySpec to send to the server. :param key_spec: KeySpec with symmetric algorithm and bit_length :returns: dictionary holding key_id returned by server :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting symmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.SYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to the " "'generate_symmetric_key' method").format( algorithm=key_spec.alg)) object_type = enums.ObjectType.SYMMETRIC_KEY algorithm = self._create_cryptographic_algorithm_attribute( key_spec.alg) usage_mask = self._create_usage_mask_attribute(object_type) length = self._create_cryptographic_length_attribute( key_spec.bit_length) attribute_list = [algorithm, usage_mask, length] template_attribute = TemplateAttribute(attributes=attribute_list) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret " + "generation") result = self.client.create(object_type=object_type, template_attribute=template_attribute, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Symmetric key generated with " "uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret " + "generation")
def load_body(req, resp=None, validator=None): """Helper function for loading an HTTP request body from JSON. This body is placed into into a Python dictionary. :param req: The HTTP request instance to load the body from. :param resp: The HTTP response instance. :param validator: The JSON validator to enforce. :return: A dict of values from the JSON request. """ try: body = req.body_file.read(CONF.max_allowed_request_size_in_bytes) req.body_file.seek(0) except IOError: LOG.exception(u._LE("Problem reading request JSON stream.")) pecan.abort(500, u._('Read Error')) try: # TODO(jwood): Investigate how to get UTF8 format via openstack # jsonutils: # parsed_body = json.loads(raw_json, 'utf-8') parsed_body = json.loads(body) strip_whitespace(parsed_body) except ValueError: LOG.exception(u._LE("Problem loading request JSON.")) pecan.abort(400, u._('Malformed JSON')) if validator: try: parsed_body = validator.validate(parsed_body) except exception.InvalidObject as e: LOG.exception(u._LE("Failed to validate JSON information")) pecan.abort(400, str(e)) except exception.UnsupportedField as e: LOG.exception(u._LE("Provided field value is not supported")) pecan.abort(400, str(e)) except exception.LimitExceeded as e: LOG.exception(u._LE("Data limit exceeded")) pecan.abort(413, str(e)) return parsed_body
def main(): try: dm = DatabaseManager(CONF) dm.execute() except Exception as ex: if not _exception_is_successful_exit(ex): LOG.exception( u._LE('Problem seen trying to run' ' barbican db manage')) sys.stderr.write("ERROR: {0}\n".format(ex)) sys.exit(1)
def handler(inst, *args, **kwargs): try: return fn(inst, *args, **kwargs) except exc.HTTPError: LOG.exception(u._LE('Webob error seen')) raise # Already converted to Webob exception, just reraise except Exception as e: # In case intervening modules have disabled logging. LOG.logger.disabled = False status, message = api.generate_safe_exception_message( operation_name, e) LOG.exception(message) pecan.abort(status, message)
def handler(inst, *args, **kwargs): try: return fn(inst, *args, **kwargs) except exc.HTTPError as f: LOG.exception(u._LE('Webob error seen')) raise f # Already converted to Webob exception, just reraise except Exception as e: # In case intervening modules have disabled logging. LOG.logger.disabled = False status, message = api.generate_safe_exception_message( operation_name, e) LOG.exception(message) pecan.abort(status, message)
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) secret_type = secret_dto.type object_type, key_format_type = ( self._map_type_ss_to_kmip(secret_type)) if object_type is None: raise KMIPSecretStoreError( u._('Secret object type {object_type} is ' 'not supported').format(object_type=object_type)) usage_mask = self._create_usage_mask_attribute(object_type) attribute_list = [usage_mask] template_attribute = TemplateAttribute( attributes=attribute_list) secret = self._get_kmip_secret(secret_dto) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret storage") result = self.client.register( object_type=object_type, template_attribute=template_attribute, secret=secret, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Key stored with uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret storage")
def generate_asymmetric_key(self, key_spec): """Generate an asymmetric key pair. Creates KMIP attribute objects based on the given KeySpec to send to the server. The KMIP Secret Store currently does not support protecting the private key with a passphrase. :param key_spec: KeySpec with asymmetric algorithm and bit_length :returns: AsymmetricKeyMetadataDTO with the key UUIDs :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting asymmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException( key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.ASYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to " "the 'generate_asymmetric_key' method").format( algorithm=key_spec.alg)) if key_spec.passphrase: raise KMIPSecretStoreError( u._('KMIP plugin does not currently support protecting the ' 'private key with a passphrase')) algorithm = self._get_kmip_algorithm(key_spec.alg.lower()) length = key_spec.bit_length try: with self.client: LOG.debug("Opened connection to KMIP client for asymmetric " + "secret generation") public_uuid, private_uuid = self.client.create_key_pair( algorithm, length) LOG.debug("SUCCESS: Asymmetric key pair generated with " "public key uuid: %s and private key uuid: %s", public_uuid, private_uuid) private_key_metadata = {KMIPSecretStore.KEY_UUID: private_uuid} public_key_metadata = {KMIPSecretStore.KEY_UUID: public_uuid} passphrase_metadata = None return ss.AsymmetricKeyMetadataDTO(private_key_metadata, public_key_metadata, passphrase_metadata) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def generate_asymmetric_key(self, key_spec): """Generate an asymmetric key pair. Creates KMIP attribute objects based on the given KeySpec to send to the server. The KMIP Secret Store currently does not support protecting the private key with a passphrase. :param key_spec: KeySpec with asymmetric algorithm and bit_length :returns: AsymmetricKeyMetadataDTO with the key UUIDs :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting asymmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.ASYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to " "the 'generate_asymmetric_key' method").format( algorithm=key_spec.alg)) if key_spec.passphrase: raise KMIPSecretStoreError( u._('KMIP plugin does not currently support protecting the ' 'private key with a passphrase')) algorithm = self._get_kmip_algorithm(key_spec.alg) length = key_spec.bit_length try: with self.client: LOG.debug("Opened connection to KMIP client for asymmetric " + "secret generation") public_uuid, private_uuid = self.client.create_key_pair( algorithm, length) LOG.debug( "SUCCESS: Asymmetric key pair generated with " "public key uuid: %s and private key uuid: %s", public_uuid, private_uuid) private_key_metadata = {KMIPSecretStore.KEY_UUID: private_uuid} public_key_metadata = {KMIPSecretStore.KEY_UUID: public_uuid} passphrase_metadata = None return ss.AsymmetricKeyMetadataDTO(private_key_metadata, public_key_metadata, passphrase_metadata) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def handle_error(self, project, status, message, exception, project_id=None, resource_type=None, operation_type=None): LOG.error( u._LE( 'Error processing Keystone event, project_id=%(project_id)s, ' 'event resource=%(resource)s, event operation=%(operation)s, ' 'status=%(status)s, error message=%(message)s' ), { 'project_id': project.project_id, 'resource': resource_type, 'operation': operation_type, 'status': status, 'message': message } )
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) secret_type = secret_dto.type object_type, key_format_type = (self._map_type_ss_to_kmip(secret_type)) if object_type is None: raise KMIPSecretStoreError( u._('Secret object type {object_type} is ' 'not supported').format(object_type=object_type)) usage_mask = self._create_usage_mask_attribute(object_type) attribute_list = [usage_mask] template_attribute = TemplateAttribute(attributes=attribute_list) secret = self._get_kmip_secret(secret_dto) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret storage") result = self.client.register( object_type=object_type, template_attribute=template_attribute, secret=secret, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Key stored with uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret storage")
def delete_secret(self, secret_metadata): """Deletes the secret whose metadata is included in the dictionary. Returns nothing if successful, raises an exception if an error occurs :param secret_metadata: Dictionary of key metadata, requires: {'key_uuid': <uuid of key>} :raises: SecretGeneralException """ LOG.debug("Starting secret deletion with KMIP plugin") uuid = str(secret_metadata[KMIPSecretStore.KEY_UUID]) try: with self.client: LOG.debug("Opened connection to KMIP client") self.client.destroy(uuid) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def process_and_suppress_exceptions(self, *args, **kwargs): """Invokes the process() template method, suppressing all exceptions. TODO(john-wood-w) This method suppresses exceptions for flows that do not want to rollback database modifications in reaction to such exceptions, as this could also rollback the marking of the entity (eg. order) in the ERROR status via the handle_error() call below. For Liberty, we might want to consider a workflow manager instead of these process_xxxx() method as shown here: https://gist.github.com/jfwood/a8130265b0db3c793ec8 """ try: return self.process(*args, **kwargs) except Exception: LOG.exception( u._LE( "Suppressing exception while trying to " "process task '%s'."), self.get_name())
def get_secret(self, secret_type, secret_metadata): """Gets a secret :param secret_type: secret type :param secret_metadata: Dictionary of key metadata, requires: {'key_uuid': <uuid of key>} :returns: SecretDTO of the retrieved Secret :raises: SecretGeneralException """ LOG.debug("Starting secret retrieval with KMIP plugin") uuid = str(secret_metadata[KMIPSecretStore.KEY_UUID]) try: with self.client: LOG.debug("Opened connection to KMIP client for secret " + "retrieval") managed_object = self.client.get(uuid) return self._get_barbican_secret(managed_object, secret_type) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def on_delete(self, external_project_id, **kwargs): container_consumers = self.consumer_repo.get_by_container_id( self.container_id, suppress_exception=True ) try: self.container_repo.delete_entity_by_id( entity_id=self.container_id, external_project_id=external_project_id ) except exception.NotFound: LOG.exception(u._LE('Problem deleting container')) container_not_found() for consumer in container_consumers[0]: try: self.consumer_repo.delete_entity_by_id( consumer.id, external_project_id) except exception.NotFound: pass
def on_delete(self, external_project_id, **kwargs): container_consumers = self.consumer_repo.get_by_container_id( self.container_id, suppress_exception=True) try: self.container_repo.delete_entity_by_id( entity_id=self.container_id, external_project_id=external_project_id) except exception.NotFound: LOG.exception(u._LE('Problem deleting container')) container_not_found() LOG.info(u._LI('Deleted container for project: %s'), external_project_id) for consumer in container_consumers[0]: try: self.consumer_repo.delete_entity_by_id(consumer.id, external_project_id) except exception.NotFound: pass
def handler(inst, *args, **kwargs): try: return fn(inst, *args, **kwargs) except exc.HTTPError: LOG.exception(u._LE('Webob error seen')) raise # Already converted to Webob exception, just reraise # In case PolicyNotAuthorized, we do not want to expose payload by # logging exception, so just LOG.error except policy.PolicyNotAuthorized as pna: status, message = api.generate_safe_exception_message( operation_name, pna) LOG.error(message) pecan.abort(status, message) except Exception as e: # In case intervening modules have disabled logging. LOG.logger.disabled = False status, message = api.generate_safe_exception_message( operation_name, e) LOG.exception(message) pecan.abort(status, message)
def _enqueue_task(self, task): """Re-enqueue the specified task.""" retry_task_name = 'N/A' retry_args = 'N/A' retry_kwargs = 'N/A' # Start a new isolated database transaction just for this task. repositories.start() try: # Invoke queue client to place retried RPC task on queue. retry_task_name = task.retry_task retry_args = task.retry_args retry_kwargs = task.retry_kwargs retry_method = getattr(self.queue, retry_task_name) retry_method(*retry_args, **retry_kwargs) # Remove the retry record from the queue. task.status = models.States.ACTIVE self.order_retry_repo.delete_entity_by_id(task.id, None) repositories.commit() LOG.debug( "(Enqueued method '{0}' with args '{1}' and " "kwargs '{2}')".format( retry_task_name, retry_args, retry_kwargs)) except Exception: LOG.exception( u._LE( "Problem enqueuing method '%(name)s' with args '%(args)s' " "and kwargs '%(kwargs)s'."), { 'name': retry_task_name, 'args': retry_args, 'kwargs': retry_kwargs } ) repositories.rollback() finally: repositories.clear()
def get_secret(self, secret_type, secret_metadata): """Gets a secret :param secret_type: secret type :param secret_metadata: Dictionary of key metadata, requires: {'key_uuid': <uuid of key>} :returns: SecretDTO of the retrieved Secret :raises: SecretGeneralException """ LOG.debug("Starting secret retrieval with KMIP plugin") uuid = str(secret_metadata[KMIPSecretStore.KEY_UUID]) object_type, key_format_enum = self._map_type_ss_to_kmip(secret_type) if (key_format_enum is not None and object_type != enums.ObjectType.CERTIFICATE): key_format_type = misc.KeyFormatType(key_format_enum) else: key_format_type = None try: self.client.open() LOG.debug("Opened connection to KMIP client for secret " + "retrieval") result = self.client.get(uuid=uuid, key_format_type=key_format_type, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: ret_secret_dto = self._get_barbican_secret(result, secret_type) LOG.debug("SUCCESS: Key retrieved with uuid: %s", uuid) return ret_secret_dto else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret " + "retrieval")
def get_secret(self, secret_type, secret_metadata): """Gets a secret :param secret_type: secret type :param secret_metadata: Dictionary of key metadata, requires: {'key_uuid': <uuid of key>} :returns: SecretDTO of the retrieved Secret :raises: SecretGeneralException """ LOG.debug("Starting secret retrieval with KMIP plugin") uuid = str(secret_metadata[KMIPSecretStore.KEY_UUID]) object_type, key_format_enum = self._map_type_ss_to_kmip(secret_type) if key_format_enum is not None: key_format_type = misc.KeyFormatType(key_format_enum) else: key_format_type = None try: self.client.open() LOG.debug("Opened connection to KMIP client for secret " + "retrieval") result = self.client.get(uuid=uuid, key_format_type=key_format_type, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: secret_block = result.secret.key_block key_value_type = type(secret_block.key_value.key_material) if (key_value_type == kmip_objects.KeyMaterialStruct or key_value_type == kmip_objects.KeyMaterial): secret_value = self._denormalize_secret( secret_block.key_value.key_material.value, secret_type) else: msg = u._( "Unknown key value type received from KMIP " "server, expected {key_value_struct} or " "{key_value_string}, received: {key_value_type}" ).format( key_value_struct=kmip_objects.KeyValue, key_value_string=kmip_objects.KeyMaterial, key_value_type=key_value_type ) LOG.exception(msg) raise ss.SecretGeneralException(msg) secret_alg = self._map_algorithm_kmip_to_ss( secret_block.cryptographic_algorithm.value) secret_bit_length = secret_block.cryptographic_length.value ret_secret_dto = ss.SecretDTO( secret_type, secret_value, ss.KeySpec(secret_alg, secret_bit_length), content_type=None, transport_key=None) LOG.debug("SUCCESS: Key retrieved with uuid: %s", uuid) return ret_secret_dto else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret " + "retrieval")
def generate_asymmetric_key(self, key_spec): """Generate an asymmetric key pair. Creates KMIP attribute objects based on the given KeySpec to send to the server. The KMIP Secret Store currently does not support protecting the private key with a passphrase. :param key_spec: KeySpec with asymmetric algorithm and bit_length :returns: AsymmetricKeyMetadataDTO with the key UUIDs :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting asymmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException( key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.ASYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to " "the 'generate_asymmetric_key' method").format( algorithm=key_spec.alg)) if key_spec.passphrase: raise KMIPSecretStoreError( u._('KMIP plugin does not currently support protecting the ' 'private key with a passphrase')) algorithm = self._create_cryptographic_algorithm_attribute( key_spec.alg) length = self._create_cryptographic_length_attribute( key_spec.bit_length) attributes = [algorithm, length] common = CommonTemplateAttribute( attributes=attributes) try: self.client.open() LOG.debug("Opened connection to KMIP client for asymmetric " + "secret generation") result = self.client.create_key_pair( common_template_attribute=common, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Asymmetric key pair generated with " "public key uuid: %s and private key uuid: %s", result.public_key_uuid.value, result.private_key_uuid.value) private_key_metadata = { KMIPSecretStore.KEY_UUID: result.private_key_uuid.value} public_key_metadata = { KMIPSecretStore.KEY_UUID: result.public_key_uuid.value} passphrase_metadata = None return ss.AsymmetricKeyMetadataDTO(private_key_metadata, public_key_metadata, passphrase_metadata) else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for asymmetric " "secret generation")