summaryrefslogtreecommitdiff
path: root/passlib/exc.py
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2020-10-05 21:14:03 -0400
committerEli Collins <elic@assurancetechnologies.com>2020-10-05 21:14:03 -0400
commita2809fd98ed58eb006d204b05cc1519bdf1b12de (patch)
treea6e47b8f2ddecf8a01aded663a151dacbef70b7a /passlib/exc.py
parent0b6c5bdc88ace23e7f609ef9ef72da92495dddab (diff)
downloadpasslib-a2809fd98ed58eb006d204b05cc1519bdf1b12de.tar.gz
passlib.handlers: cases where crypt() returns malformed hash
now return a single unified InternalBackendError() class, instead of AssertionError. This change has a couple of parts: * assert statements replaced with permanent checks, since crypt() is unpredictable enough that we need to have this always on, even if production runs code in "-O2" mode. * added debug_only_repr() helper which allows including sensitive stuff like salts & hash digests within error tracebacks -- will only do so when global flag is enabled; and that's currently only set by unittest suite. * added new InternalBackendError() exception class (a RuntimeError subclass); which is raised instead of an AssertionError.
Diffstat (limited to 'passlib/exc.py')
-rw-r--r--passlib/exc.py49
1 files changed, 49 insertions, 0 deletions
diff --git a/passlib/exc.py b/passlib/exc.py
index 280043d..4539c7d 100644
--- a/passlib/exc.py
+++ b/passlib/exc.py
@@ -15,6 +15,10 @@ class UnknownBackendError(ValueError):
message = "%s: unknown backend: %r" % (hasher.name, backend)
ValueError.__init__(self, message)
+
+# XXX: add a PasslibRuntimeError as base for Missing/Internal/Security runtime errors?
+
+
class MissingBackendError(RuntimeError):
"""Error raised if multi-backend handler has no available backends;
or if specifically requested backend is not available.
@@ -28,6 +32,15 @@ class MissingBackendError(RuntimeError):
"""
+class InternalBackendError(RuntimeError):
+ """
+ Error raised if something unrecoverable goes wrong with backend call;
+ such as if ``crypt.crypt()`` returning a malformed hash.
+
+ .. versionadded:: 1.7.3
+ """
+
+
class PasswordValueError(ValueError):
"""
Error raised if a password can't be hashed / verified for various reasons.
@@ -102,6 +115,7 @@ class PasswordTruncateError(PasswordSizeError):
(cls.name, cls.truncate_size))
PasswordSizeError.__init__(self, cls.truncate_size, msg)
+
class PasslibSecurityError(RuntimeError):
"""
Error raised if critical security issue is detected
@@ -338,5 +352,40 @@ def ChecksumSizeError(handler, raw=False):
return MalformedHashError(handler, reason)
#=============================================================================
+# sensitive info helpers
+#=============================================================================
+
+#: global flag, set temporarily by UTs to allow debug_only_repr() to display sensitive values.
+ENABLE_DEBUG_ONLY_REPR = False
+
+
+def debug_only_repr(value, param="hash"):
+ """
+ helper used to display sensitive data (hashes etc) within error messages.
+ currently returns placeholder test UNLESS unittests are running,
+ in which case the real value is displayed.
+
+ mainly useful to prevent hashes / secrets from being exposed in production tracebacks;
+ while still being visible from test failures.
+
+ NOTE: api subject to change, may formalize this more in the future.
+ """
+ if ENABLE_DEBUG_ONLY_REPR or value is None or isinstance(value, bool):
+ return repr(value)
+ return "<%s %s value omitted>" % (param, type(value))
+
+
+def CryptBackendError(handler, config, hash, # *
+ source="crypt.crypt()"):
+ """
+ helper to generate standard message when ``crypt.crypt()`` returns invalid result.
+ takes care of automatically masking contents of config & hash outside of UTs.
+ """
+ name = _get_name(handler)
+ msg = "%s returned invalid %s hash: config=%s hash=%s" % \
+ (source, name, debug_only_repr(config), debug_only_repr(hash))
+ raise InternalBackendError(msg)
+
+#=============================================================================
# eof
#=============================================================================