changeset 8272:1e0632b6ec27

auth: also use safe password hashing on Windows using bcrypt For unknown reasons, Kallithea used different hashing algorithms on Windows and Posix. Perhaps because problems with bcrypt on Windows in the past. That should no longer be an issue, and it doesn't make sense to have different security properties on the platforms. While changing to bcrypt everywhere, also remain backwards compatible and accept existing passwords hashed with sha256 - both on Windows (where it used to be used), and elsewhere (in case a system has been migrated from Windows to Unix).
author Mads Kiilerich <mads@kiilerich.com>
date Mon, 30 Dec 2019 01:02:36 +0100
parents 2ce0bc6e85f1
children db1fb0a3e7f0
files kallithea/lib/auth.py setup.py
diffstat 2 files changed, 17 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/lib/auth.py	Sun Aug 04 18:35:21 2019 +0200
+++ b/kallithea/lib/auth.py	Mon Dec 30 01:02:36 2019 +0100
@@ -30,6 +30,7 @@
 import os
 import string
 
+import bcrypt
 import ipaddr
 from decorator import decorator
 from sqlalchemy.orm import joinedload
@@ -38,7 +39,6 @@
 from tg.i18n import ugettext as _
 from webob.exc import HTTPForbidden, HTTPFound
 
-from kallithea import __platform__, is_unix, is_windows
 from kallithea.config.routing import url
 from kallithea.lib.caching_query import FromCache
 from kallithea.lib.utils import conditional_cache, get_repo_group_slug, get_repo_slug, get_user_group_slug
@@ -87,44 +87,34 @@
 
 def get_crypt_password(password):
     """
-    Cryptographic function used for password hashing based on pybcrypt
-    or Python's own OpenSSL wrapper on windows
+    Cryptographic function used for bcrypt password hashing.
 
     :param password: password to hash
     """
-    if is_windows:
-        return hashlib.sha256(password).hexdigest()
-    elif is_unix:
-        import bcrypt
-        return ascii_str(bcrypt.hashpw(safe_bytes(password), bcrypt.gensalt(10)))
-    else:
-        raise Exception('Unknown or unsupported platform %s'
-                        % __platform__)
+    return ascii_str(bcrypt.hashpw(safe_bytes(password), bcrypt.gensalt(10)))
 
 
 def check_password(password, hashed):
     """
-    Checks matching password with it's hashed value, runs different
-    implementation based on platform it runs on
+    Checks password match the hashed value using bcrypt.
+    Remains backwards compatible and accept plain sha256 hashes which used to
+    be used on Windows.
 
     :param password: password
     :param hashed: password in hashed form
     """
     # sha256 hashes will always be 64 hex chars
     # bcrypt hashes will always contain $ (and be shorter)
-    if is_windows or len(hashed) == 64 and all(x in string.hexdigits for x in hashed):
-        return hashlib.sha256(safe_bytes(password)).hexdigest() == hashed
-    elif is_unix:
-        import bcrypt
-        try:
-            return bcrypt.checkpw(safe_bytes(password), ascii_bytes(hashed))
-        except ValueError as e:
-            # bcrypt will throw ValueError 'Invalid hashed_password salt' on all password errors
-            log.error('error from bcrypt checking password: %s', e)
-            return False
-    else:
-        raise Exception('Unknown or unsupported platform %s'
-                        % __platform__)
+    if len(hashed) == 64 and all(x in string.hexdigits for x in hashed):
+        return hashlib.sha256(password).hexdigest() == hashed
+    try:
+        return bcrypt.checkpw(safe_bytes(password), ascii_bytes(hashed))
+    except ValueError as e:
+        # bcrypt will throw ValueError 'Invalid hashed_password salt' on all password errors
+        log.error('error from bcrypt checking password: %s', e)
+        return False
+    log.error('check_password failed - no method found for hash length %s', len(hashed))
+    return False
 
 
 def _cached_perms_data(user_id, user_is_admin):
--- a/setup.py	Sun Aug 04 18:35:21 2019 +0200
+++ b/setup.py	Mon Dec 30 01:02:36 2019 +0100
@@ -71,11 +71,9 @@
     "ipaddr >= 2.2.0, < 2.3",
     "paginate >= 0.5, < 0.6",
     "paginate_sqlalchemy >= 0.3.0, < 0.4",
+    "bcrypt >= 3.1.0, < 3.2",
 ]
 
-if not is_windows:
-    requirements.append("bcrypt >= 3.1.0, < 3.2")
-
 dependency_links = [
 ]