fix: Prevent login via credentials when Auth Method is Mealie (#4370)

This commit is contained in:
Carter
2024-10-16 09:34:51 -05:00
committed by GitHub
parent 03485ecc73
commit 80caa5ffaf
4 changed files with 47 additions and 7 deletions

View File

@@ -7,6 +7,7 @@ from mealie.core.config import get_app_settings
from mealie.core.exceptions import UserLockedOut
from mealie.core.security.hasher import get_hasher
from mealie.core.security.providers.auth_provider import AuthProvider
from mealie.db.models.users.users import AuthMethod
from mealie.repos.all_repositories import get_repositories
from mealie.schema.user.auth import CredentialsRequest
from mealie.services.user_services.user_service import UserService
@@ -27,11 +28,13 @@ class CredentialsProvider(AuthProvider[CredentialsRequest]):
user = self.try_get_user(self.data.username)
if not user:
# To prevent user enumeration we perform the verify_password computation to ensure
# server side time is relatively constant and not vulnerable to timing attacks.
CredentialsProvider.verify_password(
"abc123cba321",
"$2b$12$JdHtJOlkPFwyxdjdygEzPOtYmdQF5/R5tHxw5Tq8pxjubyLqdIX5i",
self.verify_fake_password()
return None
if user.auth_method != AuthMethod.MEALIE:
self.verify_fake_password()
self._logger.warning(
"Found user but their auth method is not 'Mealie'. Unable to continue with credentials login"
)
return None
@@ -52,6 +55,14 @@ class CredentialsProvider(AuthProvider[CredentialsRequest]):
user = db.users.update(user.id, user)
return self.get_access_token(user, self.data.remember_me) # type: ignore
def verify_fake_password(self):
# To prevent user enumeration we perform the verify_password computation to ensure
# server side time is relatively constant and not vulnerable to timing attacks.
CredentialsProvider.verify_password(
"abc123cba321",
"$2b$12$JdHtJOlkPFwyxdjdygEzPOtYmdQF5/R5tHxw5Tq8pxjubyLqdIX5i",
)
@staticmethod
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""Compares a plain string to a hashed password"""

View File

@@ -23,9 +23,13 @@ class LDAPProvider(CredentialsProvider):
self.conn = None
def authenticate(self) -> tuple[str, timedelta] | None:
"""Attempt to authenticate a user given a username and password"""
"""Attempt to authenticate a user given a username and password against an LDAP provider"""
# When LDAP is enabled, we need to still also support authentication with Mealie backend
# First we look to see if we have a user. If we don't we'll attempt to create one with LDAP
# If we do find a user, we will check if their auth method is LDAP and attempt to authenticate
# Otherwise, we will proceed with Mealie authentication
user = self.try_get_user(self.data.username)
if not user or user.password == "LDAP" or user.auth_method == AuthMethod.LDAP:
if not user or user.auth_method == AuthMethod.LDAP:
user = self.get_user()
if user:
return self.get_access_token(user, self.data.remember_me)