mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 23:37:18 +00:00
feat: notify users about outdated password hashes used
This commit is contained in:
parent
20e7ba3b1d
commit
3fa3cc46ad
@ -59,10 +59,10 @@ class Mapping(Auth):
|
||||
"""
|
||||
if password is None:
|
||||
return False # invalid data supplied
|
||||
user = self.get_user(username)
|
||||
user = await self.get_user(username)
|
||||
return user is not None and user.check_credentials(password, self.salt)
|
||||
|
||||
def get_user(self, username: str) -> User | None:
|
||||
async def get_user(self, username: str) -> User | None:
|
||||
"""
|
||||
retrieve user from in-memory mapping
|
||||
|
||||
@ -84,7 +84,7 @@ class Mapping(Auth):
|
||||
Returns:
|
||||
bool: ``True`` in case if user is known and can be authorized and ``False`` otherwise
|
||||
"""
|
||||
return username is not None and self.get_user(username) is not None
|
||||
return username is not None and await self.get_user(username) is not None
|
||||
|
||||
async def verify_access(self, username: str, required: UserAccess, context: str | None) -> bool:
|
||||
"""
|
||||
@ -98,5 +98,5 @@ class Mapping(Auth):
|
||||
Returns:
|
||||
bool: ``True`` in case if user is allowed to do this request and ``False`` otherwise
|
||||
"""
|
||||
user = self.get_user(username)
|
||||
user = await self.get_user(username)
|
||||
return user is not None and user.verify_access(required)
|
||||
|
@ -120,7 +120,7 @@ class PAM(Mapping):
|
||||
bool: ``True`` in case if user is allowed to do this request and ``False`` otherwise
|
||||
"""
|
||||
# this method is basically inverted, first we check overrides in database and then fallback to the PAM logic
|
||||
if (user := self.get_user(username)) is not None:
|
||||
if (user := await self.get_user(username)) is not None:
|
||||
return user.verify_access(required)
|
||||
# if username is in admin group, then we treat it as full access
|
||||
if username in self.group_members(self.full_access_group):
|
||||
|
@ -99,6 +99,8 @@ class User:
|
||||
Returns:
|
||||
bool: ``True`` in case if password matches, ``False`` otherwise
|
||||
"""
|
||||
if self.password.startswith("$6$"):
|
||||
raise DeprecationWarning("SHA512 passwords are not longer supported")
|
||||
try:
|
||||
return bcrypt.checkpw((password + salt).encode("utf8"), self.password.encode("utf8"))
|
||||
except ValueError:
|
||||
|
@ -31,27 +31,27 @@ async def test_check_credentials_unknown(mapping: Mapping, user: User) -> None:
|
||||
assert not await mapping.check_credentials(user.username, user.password)
|
||||
|
||||
|
||||
def test_get_user(mapping: Mapping, user: User, mocker: MockerFixture) -> None:
|
||||
async def test_get_user(mapping: Mapping, user: User, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return user from storage by username
|
||||
"""
|
||||
mocker.patch("ahriman.core.database.SQLite.user_get", return_value=user)
|
||||
assert mapping.get_user(user.username) == user
|
||||
assert await mapping.get_user(user.username) == user
|
||||
|
||||
|
||||
def test_get_user_normalized(mapping: Mapping, user: User, mocker: MockerFixture) -> None:
|
||||
async def test_get_user_normalized(mapping: Mapping, user: User, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return user from storage by username case-insensitive
|
||||
"""
|
||||
mocker.patch("ahriman.core.database.SQLite.user_get", return_value=user)
|
||||
assert mapping.get_user(user.username.upper()) == user
|
||||
assert await mapping.get_user(user.username.upper()) == user
|
||||
|
||||
|
||||
def test_get_user_unknown(mapping: Mapping, user: User) -> None:
|
||||
async def test_get_user_unknown(mapping: Mapping, user: User) -> None:
|
||||
"""
|
||||
must return None in case if no user found
|
||||
"""
|
||||
assert mapping.get_user(user.username) is None
|
||||
assert await mapping.get_user(user.username) is None
|
||||
|
||||
|
||||
async def test_known_username(mapping: Mapping, user: User, mocker: MockerFixture) -> None:
|
||||
|
@ -1,3 +1,5 @@
|
||||
import pytest
|
||||
|
||||
from dataclasses import replace
|
||||
|
||||
from ahriman.models.user import User
|
||||
@ -25,6 +27,19 @@ def test_check_credentials_empty_hash(user: User) -> None:
|
||||
assert not user.check_credentials(current_password, "salt")
|
||||
|
||||
|
||||
def test_check_credentials_sha512() -> None:
|
||||
"""
|
||||
must raise DeprecationWarning for sha512 hashed passwords
|
||||
"""
|
||||
user = User(
|
||||
username="user",
|
||||
password="$6$rounds=656000$mWBiecMPrHAL1VgX$oU4Y5HH8HzlvMaxwkNEJjK13ozElyU1wAHBoO/WW5dAaE4YEfnB0X3FxbynKMl4FBdC3Ovap0jINz4LPkNADg0",
|
||||
access=UserAccess.Read,
|
||||
)
|
||||
with pytest.raises(DeprecationWarning):
|
||||
assert user.check_credentials("password", "salt")
|
||||
|
||||
|
||||
def test_hash_password_empty_hash(user: User) -> None:
|
||||
"""
|
||||
must return empty string after hash in case if password not set
|
||||
|
Loading…
Reference in New Issue
Block a user