fix(auth): api_key condivisa fra postazioni, timing costante al login (#25)
login_user riusa l'api_key esistente invece di rigenerarla ad ogni
login: due postazioni collegate con lo stesso utente restavano
altrimenti disconnesse a vicenda. logout_user diventa no-op sulla key
a meno di all_sessions=True (nuovo parametro, passato da
POST /api/auth/logout?all_sessions=true nel router).
authenticate_user esegue comunque bcrypt.checkpw contro un hash fittizio
quando lo username non esiste, per non rivelare col tempo di risposta
se uno username è registrato.
PUT /api/users/{id}/password azzera l'api_key dell'utente dopo il
cambio, come già fa setup.py:634.
Non introdotto in questa issue: hashing o scadenza della api_key
(annotato come MANCA nel rapporto del lotto).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,11 +34,15 @@ async def login(data: LoginRequest, db: AsyncSession = Depends(get_db)):
|
||||
|
||||
@router.post("/logout", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def logout(
|
||||
all_sessions: bool = False,
|
||||
user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Logout - invalidate API key."""
|
||||
await logout_user(db, user)
|
||||
"""Logout. The API key is shared across stations logged in as the same
|
||||
user, so by default this does not invalidate it - only this station's
|
||||
session (its Flask session, on the client side) ends. Pass
|
||||
?all_sessions=true to invalidate the key everywhere."""
|
||||
await logout_user(db, user, all_sessions=all_sessions)
|
||||
|
||||
|
||||
@router.get("/me", response_model=UserResponse)
|
||||
|
||||
@@ -100,12 +100,17 @@ async def change_user_password(
|
||||
admin: User = Depends(require_admin_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Change user password (admin only)."""
|
||||
"""Change user password (admin only). Invalidates the user's API key,
|
||||
|
||||
the same as setup.py's change-user-password: a password change should
|
||||
force everyone logged in as that user to log back in.
|
||||
"""
|
||||
result = await db.execute(select(User).where(User.id == user_id))
|
||||
user = result.scalar_one_or_none()
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
user.password_hash = hash_password(data.password)
|
||||
user.api_key = None
|
||||
await db.flush()
|
||||
return {"message": f"Password changed for user {user.username}"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user