Switch to crypt from passlib

Next step in getting rid of `passlib` is sha512_crypt. This one is
tricky since the `crypt` lib is deprecated in py311 and dropped in py313
with the only replacement by `passlib`. But since passlib itself is
abandoned it literally means there is nothing we could use.

On the other hand `sha512_crypt` was "deprecated" already in pike and it
is not possible to enable it in Keystone while old passwords are still
supported.

In this unlucky situation still get rid of passlib and support for this
algorightm is going to be completely dropped in next Keystone release.

Change-Id: If791c953bc2953f2c78ff91e4fc4a342b89d6d1b
This commit is contained in:
Artem Goncharov 2024-09-23 13:41:09 +02:00
parent 364e8bb712
commit 02583542c0
4 changed files with 68 additions and 1 deletions

View File

@ -0,0 +1,39 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import crypt
from keystone.common import password_hashers
class Sha512_crypt(password_hashers.PasswordHasher):
"""passlib transition class for sha512_crypt password hashing"""
name: str = "sha512_crypt"
ident: str = "$6$"
@staticmethod
def verify(password: bytes, hashed: str) -> bool:
"""Verify hashing password would be equal to the `hashed` value
:param bytes password: Password to verify
:param string hashed: Hashed password. Used to extract hashing
parameters
:returns: boolean whether hashing password with the same parameters
would match hashed value
"""
return (
crypt.crypt(password.decode("utf8"), hashed[0 : hashed.rfind("$")])
== hashed
)

View File

@ -20,6 +20,7 @@ import passlib.hash
from keystone.common.password_hashers import bcrypt
from keystone.common.password_hashers import scrypt
from keystone.common.password_hashers import sha512_crypt
import keystone.conf
from keystone import exception
from keystone.i18n import _
@ -30,10 +31,10 @@ LOG = log.getLogger(__name__)
SUPPORTED_HASHERS = frozenset(
[
passlib.hash.pbkdf2_sha512,
passlib.hash.sha512_crypt,
scrypt.Scrypt,
bcrypt.Bcrypt,
bcrypt.Bcrypt_sha256,
sha512_crypt.Sha512_crypt,
]
)

View File

@ -134,3 +134,23 @@ class TestPasswordHashing(unit.BaseTestCase):
self.assertTrue(
password_hashing.check_password(password, hashed_passlib)
)
def test_sha512_crypt_passlib_compat(self):
self.config_fixture.config(strict_password_check=True)
# sha512_crypt is deprecated and is not supported to be set.
# We want to ensure that user is still able to login, thus
# set algo to whatever and go verify pwd
self.config_fixture.config(
group="identity", password_hash_algorithm="bcrypt"
)
self.config_fixture.config(group="identity", max_password_length="72")
# few iterations to test multiple random values
for _ in range(self.ITERATIONS):
password: str = "".join( # type: ignore
secrets.choice(string.printable)
for i in range(random.randint(1, 72))
)
hashed_passlib = passlib.hash.sha512_crypt.hash(password)
self.assertTrue(
password_hashing.check_password(password, hashed_passlib)
)

View File

@ -0,0 +1,7 @@
---
deprecations:
- |
This is the last release where passwords hashed using sha512_crypt
algorithm are supported. Since even support of that is being dropped in
python 3.13 it would be physically dropped from Keystone in the next
release (`Epoxy`).