]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Adding method get_hashing_schema() to class LdapPasswordHandler
authorFrank Brehm <frank.brehm@pixelpark.com>
Fri, 18 Aug 2023 16:01:03 +0000 (18:01 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Fri, 18 Aug 2023 16:01:03 +0000 (18:01 +0200)
lib/pp_admintools/handler/ldap_password.py

index e100956f887510a3379041293a06ad499b310f79..a59686243949e8a0c7cd549d25c3a2f5f8e9cf00 100644 (file)
@@ -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__':