barbican/barbican/common/exception.py
Douglas Mendizábal 70aac1f698 Ignore network errors during C_Finalize
The Trustway Proteccio HSM can somtimes return a network error when
attempting to finalize the cryptoki library.

The error can prevent reinitialization because we attempt to finalize
the library before initalizing a new connection.  When a network error
occurrs, barbican gets stuck in an error loop trying to finalize the
dead connection before starting a new one.

This patch adds code to ignore the network error when finalizing to
ensure we are able to attempt to reinitialize.

Connection errors during other operations will still result in 500
errors as expected.

Change-Id: I9ac6c7bbda0f81cb26e1c589803317df1ef11f39
2021-09-17 13:36:03 -05:00

401 lines
13 KiB
Python

# Copyright (c) 2013-2014 Rackspace, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Barbican exception subclasses
"""
from barbican import i18n as u
_FATAL_EXCEPTION_FORMAT_ERRORS = False
class BarbicanException(Exception):
"""Base Barbican Exception
To correctly use this class, inherit from it and define
a 'message' property. That message will get printf'd
with the keyword arguments provided to the constructor.
"""
message = u._("An unknown exception occurred")
def __init__(self, message_arg=None, *args, **kwargs):
if not message_arg:
message_arg = self.message
try:
self.message = message_arg % kwargs
except Exception as e:
if _FATAL_EXCEPTION_FORMAT_ERRORS:
raise e
else:
# at least get the core message out if something happened
pass
super(BarbicanException, self).__init__(self.message)
class BarbicanHTTPException(BarbicanException):
"""Base Barbican Exception to handle HTTP responses
To correctly use this class, inherit from it and define the following
properties:
- message: The message that will be displayed in the server log.
- client_message: The message that will actually be outputted to the
client.
- status_code: The HTTP status code that should be returned.
The default status code is 500.
"""
client_message = u._("failure seen - please contact site administrator.")
status_code = 500
def __init__(self, message_arg=None, client_message=None, *args, **kwargs):
if not client_message:
client_message = self.client_message
try:
self.client_message = client_message % kwargs
except Exception as e:
if _FATAL_EXCEPTION_FORMAT_ERRORS:
raise e
else:
# at least get the core message out if something happened
pass
super(BarbicanHTTPException, self).__init__(
message_arg, self.client_message, *args, **kwargs)
class MissingArgumentError(BarbicanException):
message = u._("Missing required argument.")
class MissingMetadataField(BarbicanHTTPException):
message = u._("Missing required metadata field for %(required)s")
client_message = message
status_code = 400
class InvalidMetadataRequest(BarbicanHTTPException):
message = u._("Invalid Metadata. Keys and Values must be Strings.")
client_message = message
status_code = 400
class InvalidMetadataKey(BarbicanHTTPException):
message = u._("Invalid Key. Key must be URL safe.")
client_message = message
status_code = 400
class InvalidSubjectDN(BarbicanHTTPException):
message = u._("Invalid subject DN: %(subject_dn)s")
client_message = message
status_code = 400
class InvalidContainer(BarbicanHTTPException):
message = u._("Invalid container: %(reason)s")
client_message = message
status_code = 400
class InvalidExtensionsData(BarbicanHTTPException):
message = u._("Invalid extensions data.")
client_message = message
status_code = 400
class InvalidCMCData(BarbicanHTTPException):
message = u._("Invalid CMC Data")
client_message = message
status_code = 400
class InvalidPKCS10Data(BarbicanHTTPException):
message = u._("Invalid PKCS10 Data: %(reason)s")
client_message = message
status_code = 400
class InvalidCertificateRequestType(BarbicanHTTPException):
message = u._("Invalid Certificate Request Type")
client_message = message
status_code = 400
class CertificateExtensionsNotSupported(BarbicanHTTPException):
message = u._("Extensions are not yet supported. "
"Specify a valid profile instead.")
client_message = message
status_code = 400
class FullCMCNotSupported(BarbicanHTTPException):
message = u._("Full CMC Requests are not yet supported.")
client_message = message
status_code = 400
class NotFound(BarbicanException):
message = u._("An object with the specified identifier was not found.")
class ConstraintCheck(BarbicanException):
message = u._("A defined SQL constraint check failed: %(error)s")
class NotSupported(BarbicanException):
message = u._("Operation is not supported.")
class Invalid(BarbicanException):
message = u._("Data supplied was not valid.")
class NoDataToProcess(BarbicanHTTPException):
message = u._("No data supplied to process.")
client_message = message
status_code = 400
class LimitExceeded(BarbicanHTTPException):
message = u._("The request returned a 413 Request Entity Too Large. This "
"generally means that rate limiting or a quota threshold "
"was breached.")
client_message = u._("Provided information too large to process")
status_code = 413
def __init__(self, *args, **kwargs):
super(LimitExceeded, self).__init__(*args, **kwargs)
self.retry_after = (int(kwargs['retry']) if kwargs.get('retry')
else None)
class InvalidObject(BarbicanHTTPException):
status_code = 400
def __init__(self, *args, **kwargs):
self.invalid_property = kwargs.get('property')
self.message = u._("Failed to validate JSON information: ")
self.client_message = u._("Provided object does not match "
"schema '{schema}': "
"{reason}. Invalid property: "
"'{property}'").format(*args, **kwargs)
self.message = self.message + self.client_message
super(InvalidObject, self).__init__(*args, **kwargs)
class PayloadDecodingError(BarbicanHTTPException):
status_code = 400
message = u._("Error while attempting to decode payload.")
client_message = u._("Unable to decode request data.")
class UnsupportedField(BarbicanHTTPException):
message = u._("No support for value set on field '%(field)s' on "
"schema '%(schema)s': %(reason)s")
client_message = u._("Provided field value is not supported")
status_code = 400
def __init__(self, *args, **kwargs):
super(UnsupportedField, self).__init__(*args, **kwargs)
self.invalid_field = kwargs.get('field')
class FeatureNotImplemented(BarbicanException):
message = u._("Feature not implemented for value set on field "
"'%(field)s' on " "schema '%(schema)s': %(reason)s")
def __init__(self, *args, **kwargs):
super(FeatureNotImplemented, self).__init__(*args, **kwargs)
self.invalid_field = kwargs.get('field')
class StoredKeyContainerNotFound(BarbicanException):
message = u._("Container %(container_id)s does not exist for stored "
"key certificate generation.")
class StoredKeyPrivateKeyNotFound(BarbicanException):
message = u._("Container %(container_id)s does not reference a private "
"key needed for stored key certificate generation.")
class ProvidedTransportKeyNotFound(BarbicanHTTPException):
message = u._("Provided Transport key %(transport_key_id)s "
"could not be found")
client_message = u._("Provided transport key was not found.")
status_code = 400
class InvalidCAID(BarbicanHTTPException):
message = u._("Invalid CA_ID: %(ca_id)s")
client_message = u._("The ca_id provided in the request is invalid")
status_code = 400
class CANotDefinedForProject(BarbicanHTTPException):
message = u._("CA specified by ca_id %(ca_id)s not defined for project: "
"%(project_id)s")
client_message = u._("The ca_id provided in the request is not defined "
"for this project")
status_code = 403
class QuotaReached(BarbicanHTTPException):
message = u._("Quota reached for project %(external_project_id)s. Only "
"%(quota)s %(resource_type)s are allowed.")
client_message = u._("Creation not allowed because a quota has "
"been reached")
status_code = 403
def __init__(self, *args, **kwargs):
super(QuotaReached, self).__init__(*args, **kwargs)
self.external_project_id = kwargs.get('external_project_id')
self.quota = kwargs.get('quota')
self.resource_type = kwargs.get('resource_type')
class InvalidParentCA(BarbicanHTTPException):
message = u._("Invalid Parent CA: %(parent_ca_ref)s")
client_message = message
status_code = 400
class SubCAsNotSupported(BarbicanHTTPException):
message = u._("Plugin does not support generation of subordinate CAs")
client_message = message
status_code = 400
class SubCANotCreated(BarbicanHTTPException):
message = u._("Errors in creating subordinate CA: %(name)")
client_message = message
class CannotDeleteBaseCA(BarbicanHTTPException):
message = u._("Only subordinate CAs can be deleted.")
status_code = 403
class UnauthorizedSubCA(BarbicanHTTPException):
message = u._("Subordinate CA is not owned by this project")
client_message = message
status_code = 403
class CannotDeletePreferredCA(BarbicanHTTPException):
message = u._("A new project preferred CA must be set "
"before this one can be deleted.")
status_code = 409
class BadSubCACreationRequest(BarbicanHTTPException):
message = u._("Errors returned by CA when attempting to "
"create subordinate CA: %(reason)s")
client_message = message
status_code = 400
class SubCACreationErrors(BarbicanHTTPException):
message = u._("Errors returned by CA when attempting to create "
"subordinate CA: %(reason)s")
client_message = message
class SubCADeletionErrors(BarbicanHTTPException):
message = u._("Errors returned by CA when attempting to delete "
"subordinate CA: %(reason)s")
client_message = message
class PKCS11Exception(BarbicanException):
message = u._("There was an error with the PKCS#11 library.")
class P11CryptoPluginKeyException(PKCS11Exception):
message = u._("More than one key found for label")
class P11CryptoPluginException(PKCS11Exception):
message = u._("General exception")
class P11CryptoKeyHandleException(PKCS11Exception):
message = u._("No key handle was found")
class P11CryptoTokenException(PKCS11Exception):
message = u._("No token was found in slot %(slot_id)s")
class TrustwayProteccioException(PKCS11Exception):
message = u._("Trustway Proteccio HSM Error")
class MultipleStorePreferredPluginMissing(BarbicanException):
"""Raised when a preferred plugin is missing in service configuration."""
def __init__(self, store_name):
super(MultipleStorePreferredPluginMissing, self).__init__(
u._("Preferred Secret Store plugin '{store_name}' is not "
"currently set in service configuration. This is probably a "
"server misconfiguration.").format(
store_name=store_name)
)
self.store_name = store_name
class MultipleStorePluginStillInUse(BarbicanException):
"""Raised when a used plugin is missing in service configuration."""
def __init__(self, store_name):
super(MultipleStorePluginStillInUse, self).__init__(
u._("Secret Store plugin '{store_name}' is still in use and can "
"not be removed. Its missing in service configuration. This is"
" probably a server misconfiguration.").format(
store_name=store_name)
)
self.store_name = store_name
class MultipleSecretStoreLookupFailed(BarbicanException):
"""Raised when a plugin lookup suffix is missing during config read."""
def __init__(self):
msg = u._("Plugin lookup property 'stores_lookup_suffix' is not "
"defined in service configuration")
super(MultipleSecretStoreLookupFailed, self).__init__(msg)
class MultipleStoreIncorrectGlobalDefault(BarbicanException):
"""Raised when a global default for only one plugin is not set to True."""
def __init__(self, occurrence):
msg = None
if occurrence > 1:
msg = u._("There are {count} plugins with global default as "
"True in service configuration. Only one plugin can have"
" this as True").format(count=occurrence)
else:
msg = u._("There is no plugin defined with global default as True."
" One of plugin must be identified as global default")
super(MultipleStoreIncorrectGlobalDefault, self).__init__(msg)
class MultipleStorePluginValueMissing(BarbicanException):
"""Raised when a store plugin value is missing in service configuration."""
def __init__(self, section_name):
super(MultipleStorePluginValueMissing, self).__init__(
u._("In section '{0}', secret_store_plugin value is missing"
).format(section_name)
)
self.section_name = section_name