B23: политика паролей исполняется + ретенция журналов по-настоящему
- backend/password_policy.py: validate_new_password (длина, сложность буквы+цифры, сверка с текущим и историей), record_password_change (хранит ПРЕДЫДУШИЙ хэш, обрезка до password_history_count), password_expired + enforce_expiry (пометка must_change_password) - users.password_changed_at + таблица password_history (010_b23_policy) - change-password и админ-сброс теперь под полной политикой (сложность и переиспользование вместо голой длины); get_current_user проверяет срок действия каждого пароля при запросе - backend/purge_logs.py: реальный DELETE просроченных audit_events (+changes) и auth_events; POST /admin/users/maintenance/purge-logs (manage_security) + CLI python -m backend.purge_logs для cron - тесты: +19 (258 passed) — валидация/история/срок, purge/идемпотентность/403
This commit is contained in:
+14
-7
@@ -17,6 +17,7 @@ from sqlalchemy.orm import Session
|
||||
from backend.database import get_db
|
||||
from backend.logging_setup import get_logger
|
||||
from backend.models import AuthEvent, SecuritySetting, User, UserSession
|
||||
from backend.password_policy import enforce_expiry, record_password_change, validate_new_password
|
||||
|
||||
log = get_logger('auth')
|
||||
|
||||
@@ -308,6 +309,9 @@ async def get_current_user(
|
||||
headers={'WWW-Authenticate': 'Bearer'},
|
||||
)
|
||||
|
||||
# B23: срок действия пароля (security_settings) — исполняется, а не декларируется
|
||||
enforce_expiry(db, user)
|
||||
|
||||
return user
|
||||
|
||||
|
||||
@@ -407,15 +411,18 @@ def change_password(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db),
|
||||
) -> dict[str, str]:
|
||||
min_len = int(_get_setting(db, 'password_min_length', '8'))
|
||||
if not verify_password(payload.current_password, current_user.hashed_password):
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Текущий пароль неверен')
|
||||
if len(payload.new_password) < min_len:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'Минимальная длина пароля: {min_len} символов',
|
||||
)
|
||||
current_user.hashed_password = get_password_hash(payload.new_password)
|
||||
# B23: полная политика (длина, сложность, история) вместо голой длины
|
||||
try:
|
||||
validate_new_password(db, current_user, payload.new_password,
|
||||
current_hash=current_user.hashed_password)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
||||
new_hash = get_password_hash(payload.new_password)
|
||||
record_password_change(db, current_user, new_hash,
|
||||
previous_hash=current_user.hashed_password)
|
||||
current_user.hashed_password = new_hash
|
||||
current_user.must_change_password = False
|
||||
current_user.updated_at = datetime.now(timezone.utc)
|
||||
# Отзываем все сессии после смены пароля (кроме текущей — её пересоздадим)
|
||||
|
||||
Reference in New Issue
Block a user