Mercurial > kallithea
changeset 8732:710512deb83d
lib: move some auth low level helper functions to utils2
author | Mads Kiilerich <mads@kiilerich.com> |
---|---|
date | Sun, 01 Nov 2020 23:50:29 +0100 |
parents | fa0a18dc0fd5 |
children | 8f5bc94959de |
files | kallithea/lib/auth.py kallithea/lib/auth_modules/__init__.py kallithea/lib/auth_modules/auth_internal.py kallithea/lib/utils2.py kallithea/model/user.py kallithea/tests/functional/test_admin_users.py kallithea/tests/functional/test_login.py kallithea/tests/scripts/manual_test_concurrency.py |
diffstat | 8 files changed, 80 insertions(+), 85 deletions(-) [+] |
line wrap: on
line diff
--- a/kallithea/lib/auth.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/lib/auth.py Sun Nov 01 23:50:29 2020 +0100 @@ -24,13 +24,9 @@ :copyright: (c) 2013 RhodeCode GmbH, and others. :license: GPLv3, see LICENSE.md for more details. """ -import hashlib import itertools import logging -import os -import string -import bcrypt import ipaddr from decorator import decorator from sqlalchemy.orm import joinedload @@ -42,7 +38,6 @@ import kallithea from kallithea.lib import webutils from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug -from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes from kallithea.lib.vcs.utils.lazy import LazyProperty from kallithea.lib.webutils import url from kallithea.model import db, meta @@ -52,70 +47,6 @@ log = logging.getLogger(__name__) -class PasswordGenerator(object): - """ - This is a simple class for generating password from different sets of - characters - usage:: - - passwd_gen = PasswordGenerator() - #print 8-letter password containing only big and small letters - of alphabet - passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL) - """ - ALPHABETS_NUM = r'''1234567890''' - ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm''' - ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM''' - ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' - ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \ - + ALPHABETS_NUM + ALPHABETS_SPECIAL - ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM - ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL - ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM - ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM - - def gen_password(self, length, alphabet=ALPHABETS_FULL): - assert len(alphabet) <= 256, alphabet - l = [] - while len(l) < length: - i = ord(os.urandom(1)) - if i < len(alphabet): - l.append(alphabet[i]) - return ''.join(l) - - -def get_crypt_password(password): - """ - Cryptographic function used for bcrypt password hashing. - - :param password: password to hash - """ - return ascii_str(bcrypt.hashpw(safe_bytes(password), bcrypt.gensalt(10))) - - -def check_password(password, hashed): - """ - 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 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 - - PERM_WEIGHTS = db.Permission.PERM_WEIGHTS def bump_permission(permissions, key, new_perm):
--- a/kallithea/lib/auth_modules/__init__.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/lib/auth_modules/__init__.py Sun Nov 01 23:50:29 2020 +0100 @@ -20,9 +20,9 @@ import traceback from inspect import isfunction -from kallithea.lib.auth import AuthUser, PasswordGenerator +from kallithea.lib.auth import AuthUser from kallithea.lib.compat import hybrid_property -from kallithea.lib.utils2 import asbool +from kallithea.lib.utils2 import asbool, PasswordGenerator from kallithea.model import db, meta, validators from kallithea.model.user import UserModel from kallithea.model.user_group import UserGroupModel
--- a/kallithea/lib/auth_modules/auth_internal.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/lib/auth_modules/auth_internal.py Sun Nov 01 23:50:29 2020 +0100 @@ -28,7 +28,7 @@ import logging -from kallithea.lib import auth, auth_modules +from kallithea.lib import auth_modules, utils2 from kallithea.lib.compat import hybrid_property @@ -78,7 +78,7 @@ } log.debug('user data: %s', user_data) - password_match = auth.check_password(password, userobj.password) + password_match = utils2.check_password(password, userobj.password) if userobj.is_default_user: log.info('user %s authenticated correctly as anonymous user', username)
--- a/kallithea/lib/utils2.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/lib/utils2.py Sun Nov 01 23:50:29 2020 +0100 @@ -29,12 +29,16 @@ import binascii import datetime +import hashlib import json +import logging import os import re +import string import time import urllib.parse +import bcrypt import urlobject from dateutil import relativedelta from sqlalchemy.engine import url as sa_url @@ -59,6 +63,9 @@ pass +log = logging.getLogger(__name__) + + # mute pyflakes "imported but unused" assert asbool assert aslist @@ -549,3 +556,67 @@ if retries < 0: raise IOError print(complaint) + + +class PasswordGenerator(object): + """ + This is a simple class for generating password from different sets of + characters + usage:: + + passwd_gen = PasswordGenerator() + #print 8-letter password containing only big and small letters + of alphabet + passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL) + """ + ALPHABETS_NUM = r'''1234567890''' + ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm''' + ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM''' + ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' + ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \ + + ALPHABETS_NUM + ALPHABETS_SPECIAL + ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM + ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM + + def gen_password(self, length, alphabet=ALPHABETS_FULL): + assert len(alphabet) <= 256, alphabet + l = [] + while len(l) < length: + i = ord(os.urandom(1)) + if i < len(alphabet): + l.append(alphabet[i]) + return ''.join(l) + + +def get_crypt_password(password): + """ + Cryptographic function used for bcrypt password hashing. + + :param password: password to hash + """ + return ascii_str(bcrypt.hashpw(safe_bytes(password), bcrypt.gensalt(10))) + + +def check_password(password, hashed): + """ + 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 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
--- a/kallithea/model/user.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/model/user.py Sun Nov 01 23:50:29 2020 +0100 @@ -38,7 +38,7 @@ from kallithea.lib import webutils from kallithea.lib.exceptions import DefaultUserException, UserOwnsReposException -from kallithea.lib.utils2 import generate_api_key, get_current_authuser +from kallithea.lib.utils2 import check_password, generate_api_key, get_crypt_password, get_current_authuser from kallithea.model import db, forms, meta @@ -72,7 +72,6 @@ } # raises UserCreationError if it's not allowed check_allowed_create_user(user_data, cur_user) - from kallithea.lib.auth import get_crypt_password new_user = db.User() for k, v in form_data.items(): @@ -110,7 +109,6 @@ if not cur_user: cur_user = getattr(get_current_authuser(), 'username', None) - from kallithea.lib.auth import check_password, get_crypt_password from kallithea.lib.hooks import check_allowed_create_user, log_create_user user_data = { 'username': username, 'password': password, @@ -194,7 +192,6 @@ email_kwargs=email_kwargs) def update(self, user_id, form_data, skip_attrs=None): - from kallithea.lib.auth import get_crypt_password skip_attrs = skip_attrs or [] user = self.get(user_id) if user.is_default_user: @@ -215,8 +212,6 @@ setattr(user, k, v) def update_user(self, user, **kwargs): - from kallithea.lib.auth import get_crypt_password - user = db.User.guess_instance(user) if user.is_default_user: raise DefaultUserException( @@ -381,13 +376,12 @@ return expected_token == token def reset_password(self, user_email, new_passwd): - from kallithea.lib import auth from kallithea.lib.celerylib import tasks user = db.User.get_by_email(user_email) if user is not None: if not self.can_change_password(user): raise Exception('trying to change password for external user') - user.password = auth.get_crypt_password(new_passwd) + user.password = get_crypt_password(new_passwd) meta.Session().commit() log.info('change password for %s', user_email) if new_passwd is None:
--- a/kallithea/tests/functional/test_admin_users.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/tests/functional/test_admin_users.py Sun Nov 01 23:50:29 2020 +0100 @@ -20,7 +20,7 @@ import kallithea from kallithea.controllers.admin.users import UsersController from kallithea.lib import webutils -from kallithea.lib.auth import check_password +from kallithea.lib.utils2 import check_password from kallithea.model import db, meta, validators from kallithea.model.user import UserModel from kallithea.tests import base
--- a/kallithea/tests/functional/test_login.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/tests/functional/test_login.py Sun Nov 01 23:50:29 2020 +0100 @@ -8,8 +8,7 @@ import kallithea.lib.celerylib.tasks from kallithea.lib import webutils -from kallithea.lib.auth import check_password -from kallithea.lib.utils2 import generate_api_key +from kallithea.lib.utils2 import check_password, generate_api_key from kallithea.model import db, meta, validators from kallithea.model.api_key import ApiKeyModel from kallithea.model.user import UserModel
--- a/kallithea/tests/scripts/manual_test_concurrency.py Sun Nov 01 23:54:39 2020 +0100 +++ b/kallithea/tests/scripts/manual_test_concurrency.py Sun Nov 01 23:50:29 2020 +0100 @@ -38,7 +38,7 @@ from sqlalchemy import engine_from_config import kallithea.config.application -from kallithea.lib.auth import get_crypt_password +from kallithea.lib.utils2 import get_crypt_password from kallithea.model import db, meta from kallithea.model.base import init_model from kallithea.model.repo import RepoModel