From ae20e6dbbdbbee5ddc5a8560f101d40d69af9f52 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sun, 20 Mar 2022 10:19:25 +0200 Subject: [PATCH 1/2] Implement part 1 of password encryption transition - Store information whether account has been migrated or not - Authenticate user either with the old or new system depending on whether they have been marked already migrated - Create new accounts as already migrated ones This first part does NOT implement migration of existing accounts. Signed-off-by: Marko Lindqvist --- freeciv-proxy/freeciv-proxy.py | 27 +++++++++++++++---- .../org/freeciv/persistence/DbManager.java | 6 ++--- .../java/org/freeciv/servlet/LoginUser.java | 21 ++++++++++++--- .../db/migration/V1_15__encrypt_mode.sql | 2 ++ 4 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 freeciv-web/src/main/resources/db/migration/V1_15__encrypt_mode.sql diff --git a/freeciv-proxy/freeciv-proxy.py b/freeciv-proxy/freeciv-proxy.py index a815f6b58..20e6eae59 100755 --- a/freeciv-proxy/freeciv-proxy.py +++ b/freeciv-proxy/freeciv-proxy.py @@ -159,17 +159,34 @@ def get_game_auth_method(self, cursor): return "password" def check_user_password(self, cursor, username, password): - query = ("select secure_hashed_password, activated from auth where lower(username)=lower(%(usr)s)") - cursor.execute(query, {'usr': username, 'pwd': password}) + # Encryption method transition period code. Clear out first query and + # compat_encrypt use after the transition period. + query = ("select digest_pw from auth where lower(username) = lower(%(usr)s)") + cursor.execute(query, {'usr': username}) + result = cursor.fetchall() + if len(result) == 0: + return True + compat_encrypt = not result[0][0] + if compat_encrypt: + query = ("select secure_hashed_password, CAST(ENCRYPT(%(pwd)s, secure_hashed_password) AS CHAR), activated from auth where lower(username)=lower(%(usr)s)") + cursor.execute(query, {'usr': username, 'pwd': password}) + else: + query = ("select secure_hashed_password, activated from auth where lower(username)=lower(%(usr)s)") + cursor.execute(query, {'usr': username}) result = cursor.fetchall() if len(result) == 0: # Unreserved user, no password needed return True - for secure_shashed_password, active in result: - if (active == 0): return False - if secure_shashed_password == hashlib.sha256(password.encode('utf-8')).hexdigest(): return True + if compat_encrypt: + for db_pass, encrypted_pass, active in result: + if (active == 0): return False + if db_pass == encrypted_pass: return True + else: + for secure_shashed_password, active in result: + if (active == 0): return False + if secure_shashed_password == hashlib.sha256(password.encode('utf-8')).hexdigest(): return True return False diff --git a/freeciv-web/src/main/java/org/freeciv/persistence/DbManager.java b/freeciv-web/src/main/java/org/freeciv/persistence/DbManager.java index 448b0fbbb..2d0c3d7aa 100644 --- a/freeciv-web/src/main/java/org/freeciv/persistence/DbManager.java +++ b/freeciv-web/src/main/java/org/freeciv/persistence/DbManager.java @@ -22,7 +22,7 @@ public static String getQueryCountServersByHost() { } public static String getQuerySaltHash() { - return " SELECT secure_hashed_password FROM auth " // + return " SELECT secure_hashed_password,digest_pw FROM auth " // + " WHERE LOWER(username) = LOWER(?) AND activated = '1' " // + " LIMIT 1 "; } @@ -148,8 +148,8 @@ public static StringBuilder getQueryUpdateServers(boolean serverExists, List Date: Sun, 20 Mar 2022 14:16:04 +0200 Subject: [PATCH 2/2] Migrate existing accounts to the new password encryption Accounts are migrated when they login the first time during the transition period. Plain-text passwords that the client sends for authentication are also encrypted with the new method, and the password encrypted with the old method are replaced by those. Signed-off-by: Marko Lindqvist --- freeciv-proxy/freeciv-proxy.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/freeciv-proxy/freeciv-proxy.py b/freeciv-proxy/freeciv-proxy.py index 20e6eae59..847d9e9b9 100755 --- a/freeciv-proxy/freeciv-proxy.py +++ b/freeciv-proxy/freeciv-proxy.py @@ -168,7 +168,7 @@ def check_user_password(self, cursor, username, password): return True compat_encrypt = not result[0][0] if compat_encrypt: - query = ("select secure_hashed_password, CAST(ENCRYPT(%(pwd)s, secure_hashed_password) AS CHAR), activated from auth where lower(username)=lower(%(usr)s)") + query = ("select secure_hashed_password, CAST(ENCRYPT(%(pwd)s, secure_hashed_password) AS CHAR), activated, id from auth where lower(username)=lower(%(usr)s)") cursor.execute(query, {'usr': username, 'pwd': password}) else: query = ("select secure_hashed_password, activated from auth where lower(username)=lower(%(usr)s)") @@ -180,9 +180,13 @@ def check_user_password(self, cursor, username, password): return True if compat_encrypt: - for db_pass, encrypted_pass, active in result: + for db_pass, encrypted_pass, active, uid in result: if (active == 0): return False - if db_pass == encrypted_pass: return True + if db_pass == encrypted_pass: + new_hash = hashlib.sha256(password.encode('utf-8')).hexdigest() + query = ("update auth set secure_hashed_password = %(pwd)s, digest_pw = TRUE where id = %(uid)s;") + cursor.execute(query, {'pwd': new_hash, 'uid': uid}) + return True else: for secure_shashed_password, active in result: if (active == 0): return False