From a35d16f9a191afbb31e2c185e87e5eec5e23122f Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Wed, 8 Mar 2023 11:42:04 +0300 Subject: auth: users: Use the same basic functions for password hashing To avoid repeating the same thing in multiple places, leading to errors and breakages, reuse the same basic functions for password hashing. --- gn3/auth/authentication/users.py | 23 +++++++++++++++++++---- main.py | 7 ++----- tests/unit/auth/fixtures/user_fixtures.py | 8 +++----- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/gn3/auth/authentication/users.py b/gn3/auth/authentication/users.py index 5ee148f..17e89ae 100644 --- a/gn3/auth/authentication/users.py +++ b/gn3/auth/authentication/users.py @@ -61,9 +61,8 @@ def valid_login(conn: db.DbConnection, user: User, password: str) -> bool: if row is None: return False - hasher = PasswordHasher() # TODO: Maybe tune the parameters here... try: - return hasher.verify(row["password"], password) + return hasher().verify(row["password"], password) except VerifyMismatchError as _vme: return False @@ -81,11 +80,27 @@ def save_user(cursor: db.DbCursor, email: str, name: str) -> User: (str(user_id), email, name)) return User(user_id, email, name) +def hasher(): + """Retrieve PasswordHasher object""" + # TODO: Maybe tune the parameters here... + # Tuneable Parameters: + # - time_cost (default: 2) + # - memory_cost (default: 102400) + # - parallelism (default: 8) + # - hash_len (default: 16) + # - salt_len (default: 16) + # - encoding (default: 'utf-8') + # - type (default: ) + return PasswordHasher() + +def hash_password(password): + """Hash the password.""" + return hasher().hash(password) + def set_user_password( cursor: db.DbCursor, user: User, password: str) -> Tuple[User, bytes]: """Set the given user's password in the database.""" - hasher = PasswordHasher() # TODO: Maybe tune the parameters here... - hashed_password = hasher.hash(password) + hashed_password = hash_password(password) cursor.execute( ("INSERT INTO user_credentials VALUES (:user_id, :hash) " "ON CONFLICT (user_id) DO UPDATE SET password=:hash"), diff --git a/main.py b/main.py index 49e5d55..1fda2d3 100644 --- a/main.py +++ b/main.py @@ -7,11 +7,11 @@ from datetime import datetime import click -from argon2 import PasswordHasher from yoyo import get_backend, read_migrations from gn3 import migrations from gn3.app import create_app +from gn3.auth.authentication.users import hash_password from gn3.auth import db @@ -36,13 +36,10 @@ def __init_dev_users__(): "name": "Test Development User", "password": "testpasswd"},) - def __hash_passwd__(passwd): - return PasswordHasher().hash(passwd) - with db.connection(app.config["AUTH_DB"]) as conn, db.cursor(conn) as cursor: cursor.executemany(dev_users_query, dev_users) cursor.executemany(dev_users_passwd, ( - {**usr, "hash": __hash_passwd__(usr["password"])} + {**usr, "hash": hash_password(usr["password"])} for usr in dev_users)) @app.cli.command() diff --git a/tests/unit/auth/fixtures/user_fixtures.py b/tests/unit/auth/fixtures/user_fixtures.py index 4e42abe..d248f54 100644 --- a/tests/unit/auth/fixtures/user_fixtures.py +++ b/tests/unit/auth/fixtures/user_fixtures.py @@ -2,10 +2,9 @@ import uuid import pytest -import bcrypt from gn3.auth import db -from gn3.auth.authentication.users import User +from gn3.auth.authentication.users import User, hash_password TEST_USERS = ( User(uuid.UUID("ecb52977-3004-469e-9428-2a1856725c7f"), "group@lead.er", @@ -50,9 +49,8 @@ def fxtr_users_with_passwords(fxtr_users): # pylint: disable=[redefined-outer-na """Fixture: add passwords to the users""" conn, users = fxtr_users user_passwords_params = tuple( - (str(user.user_id), bcrypt.hashpw( - f"password_for_user_{idx:03}".encode("utf8"), - bcrypt.gensalt())) + (str(user.user_id), hash_password( + f"password_for_user_{idx:03}".encode("utf8"))) for idx, user in enumerate(users, start=1)) with db.cursor(conn) as cursor: -- cgit v1.2.3