From 0e151db42dc06f2856f4913f2b8b2ab6ab9adaaf Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Fri, 18 Aug 2023 18:01:03 +0200 Subject: [PATCH] Adding method get_hashing_schema() to class LdapPasswordHandler --- lib/pp_admintools/handler/ldap_password.py | 59 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/pp_admintools/handler/ldap_password.py b/lib/pp_admintools/handler/ldap_password.py index e100956..a596862 100644 --- a/lib/pp_admintools/handler/ldap_password.py +++ b/lib/pp_admintools/handler/ldap_password.py @@ -10,6 +10,7 @@ from __future__ import absolute_import # Standard modules import logging +import re # Third party modules @@ -35,7 +36,7 @@ LOG = logging.getLogger(__name__) _ = XLATOR.gettext ngettext = XLATOR.ngettext -__version__ = '0.3.4' +__version__ = '0.4.0' # ============================================================================= @@ -110,6 +111,24 @@ class LdapPasswordHandler(HandlingObject): 'ldap_pbkdf2_sha512': 'PBKDF2_SHA512', } + crypt_ids = { + '^1$': 'CRYPT-MD5', + '^2.*': 'CRYPT-BRYPT', + '^3$': 'CRYPT-NTHASH', + '^5$': 'CRYPT-SHA256', + '^6$': 'CRYPT-SHA512', + '^7$': 'CRYPT-SCRYPT', + '^8$': 'CRYPT-PBKDF2', + '^gy$': 'CRYPT-GOSTYESCRYPT', + '^md5$': 'CRYPT-SOLARIS-MD5', + '^sha1$': 'CRYPT-PBKDF1-SHA1', + '^y$': 'CRYPT-YESCRYPT', + } + + crypt_id_re = {} + re_hash_method = re.compile(r'^\{([^\}]+)\}') + re_crypt_id = re.compile(r'^\$([^\$]+)\$') + schema_description = { 'ldap_des_crypt': _('The ancient and notorious 3 DES crypt method.'), 'ldap_md5': _('Pure {} hashing method.').format('MD5'), @@ -149,6 +168,10 @@ class LdapPasswordHandler(HandlingObject): cls.passlib_context = passlib.context.CryptContext(**context_opts) + cls.crypt_id_re = {} + for crypt_id in cls.crypt_ids.keys(): + cls.crypt_id_re[crypt_id] = re.compile(crypt_id, re.IGNORECASE) + # ------------------------------------------------------------------------- def __init__( self, appname=None, verbose=0, version=__version__, base_dir=None, @@ -432,6 +455,40 @@ class LdapPasswordHandler(HandlingObject): LOG.debug('The quality of the new password seems to be sufficient.') return True + # ------------------------------------------------------------------------- + def get_hashing_schema(self, pwd_hash): + """Get the used hashing method of the given password hash.""" + if self.verbose > 2: + LOG.debug('Password hash: {!r}'.format(pwd_hash)) + pwd_hash = pwd_hash.strip() + if not pwd_hash: + return 'EMPTY' + + m = self.re_hash_method.match(pwd_hash) + if not m: + return 'CLEAR' + method = m.group(1).upper() + if self.verbose > 2: + LOG.debug('Found raw method: {!r}'.format(method)) + if method != 'CRYPT': + return method + + bare_hash = self.re_hash_method.sub('', pwd_hash) + if self.verbose > 2: + LOG.debug('Bare hash: {!r}'.format(bare_hash)) + m = self.re_crypt_id.match(bare_hash) + if not m: + return 'CRYPT' + + crypt_id = m.group(1) + + for pattern in self.crypt_id_re.keys(): + re_id = self.crypt_id_re[pattern] + if re_id.match(crypt_id): + return self.crypt_ids[pattern] + + return 'CRYPT (unknown {!r})'.format(crypt_id) + # ============================================================================= if __name__ == '__main__': -- 2.39.5