Conversation
(cherry picked from commit ffcb72f)
There was a problem hiding this comment.
[maas-code-reviewer review]
LLM-generated review from https://github.com/canonical/maas-code-reviewer.
Intended to assist a human reviewer, not replace one — suggestions may be
incorrect, please verify before acting.
This PR successfully splits the user update requests into Self and Admin variants and correctly moves password validation into a separate check before updating. However, there are two important issues to address:
- Unintentional Overwrite of
is_staff/is_active: Hardcoding these fields toFalseandTruein theto_builder()methods causes any profile update to overwrite them. This means staff users will accidentally demote themselves when updating their names. - Event Loop Blocking: Password hashing and verification are CPU-bound operations. Running them synchronously blocks the asyncio event loop and introduces a Denial-of-Service vulnerability.
| return UserBuilder(password=password) | ||
|
|
||
|
|
||
| class UserChangePasswordRequestAdmin(BaseModel): |
There was a problem hiding this comment.
Calling UserBuilder.hash_password(...) synchronously here means that whenever this request model is converted to a builder in an async route handler, the event loop will block for the duration of the PBKDF2 hash computation (often hundreds of milliseconds). To avoid degrading API performance and preventing DoS, consider moving password hashing to the service layer where it can be offloaded to a thread pool (e.g., using anyio.to_thread.run_sync).
| await self._update_resource( | ||
| user, UserBuilder(password=hashed_password) | ||
| ) | ||
| if current_password is not None and not PBKDF2PasswordHasher().verify( |
There was a problem hiding this comment.
Running CPU-bound operations like PBKDF2PasswordHasher().verify(...) directly in an async def function will block the asyncio event loop. For security and performance reasons, offload this to a thread pool by wrapping it in await anyio.to_thread.run_sync(PBKDF2PasswordHasher().verify, current_password, user.password).
(cherry picked from commit ffcb72f)