-
Notifications
You must be signed in to change notification settings - Fork 178
fix: modify change password API v3 endpoints #655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 3.8
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ | |
| import re | ||
|
|
||
| from fastapi import Query | ||
| from pydantic import BaseModel, Field, field_validator | ||
| from pydantic import BaseModel, Field, field_validator, model_validator | ||
|
|
||
| from maasservicelayer.builders.users import UserBuilder | ||
| from maasservicelayer.db.filters import Clause | ||
|
|
@@ -81,13 +81,22 @@ def to_builder(self) -> UserBuilder: | |
| ) | ||
|
|
||
|
|
||
| class UserUpdateRequest(BaseUserRequest): | ||
| password: str | None = Field(min_length=1, default=None) | ||
| class UserUpdateRequestSelf(BaseUserRequest): | ||
| current_password: str | None = Field(min_length=1, default=None) | ||
| new_password: str | None = Field(min_length=1, default=None) | ||
|
|
||
| @model_validator(mode="after") | ||
| def check_passwords(self): | ||
| if self.new_password is not None and self.current_password is None: | ||
| raise ValueError( | ||
| "The current password must be provided when changing password." | ||
| ) | ||
| return self | ||
|
|
||
| def to_builder(self) -> UserBuilder: | ||
| password = ( | ||
| UserBuilder.hash_password(self.password) | ||
| if self.password | ||
| UserBuilder.hash_password(self.new_password) | ||
| if self.new_password is not None | ||
| else UNSET | ||
| ) | ||
| return UserBuilder( | ||
|
|
@@ -101,12 +110,42 @@ def to_builder(self) -> UserBuilder: | |
| ) | ||
|
|
||
|
|
||
| class UserUpdateRequestAdmin(UserUpdateRequest): | ||
| class UserUpdateRequestAdmin(BaseUserRequest): | ||
| password: str | None = Field(min_length=1, default=None) | ||
| groups: list[int] = Field( | ||
| default_factory=list, | ||
| description="The IDs of the groups the user will be a member of.", | ||
| ) | ||
|
|
||
| def to_builder(self) -> UserBuilder: | ||
| password = ( | ||
| UserBuilder.hash_password(self.password) | ||
| if self.password is not None | ||
| else UNSET | ||
| ) | ||
| return UserBuilder( | ||
| username=self.username, | ||
| password=password, | ||
| is_staff=False, | ||
| is_active=True, | ||
| first_name=self.first_name, | ||
| last_name=self.last_name, | ||
| email=self.email, | ||
| ) | ||
|
|
||
|
|
||
| class UserChangePasswordRequest(BaseModel): | ||
| current_password: str = Field(..., min_length=1) | ||
| new_password: str = Field(..., min_length=1) | ||
|
|
||
| def to_builder(self) -> UserBuilder: | ||
| password = UserBuilder.hash_password(self.new_password) | ||
| return UserBuilder(password=password) | ||
|
|
||
|
|
||
| class UserChangePasswordRequestAdmin(BaseModel): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| password: str = Field(..., min_length=1) | ||
|
|
||
| def to_builder(self) -> UserBuilder: | ||
| password = UserBuilder.hash_password(self.password) | ||
| return UserBuilder(password=password) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| from time import time | ||
| from typing import List | ||
|
|
||
| from django.contrib.auth.hashers import PBKDF2PasswordHasher | ||
| import structlog | ||
|
|
||
| from maascommon.constants import ( | ||
|
|
@@ -363,7 +364,9 @@ async def complete_intro(self, user_id: int) -> UserProfile: | |
| builder = UserProfileBuilder(completed_intro=True) | ||
| return await self.update_profile(user_id, builder) | ||
|
|
||
| async def change_password(self, user_id: int, password: str) -> None: | ||
| async def change_password_checks( | ||
| self, user_id: int, current_password: str | None | ||
| ) -> None: | ||
| user = await self.get_by_id(user_id) | ||
| if user is None: | ||
| raise NotFoundException() | ||
|
|
@@ -388,10 +391,17 @@ async def change_password(self, user_id: int, password: str) -> None: | |
| ] | ||
| ) | ||
|
|
||
| hashed_password = UserBuilder.hash_password(password) | ||
| 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. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running CPU-bound operations like |
||
| current_password, user.password | ||
| ): | ||
| raise BadRequestException( | ||
| details=[ | ||
| BaseExceptionDetail( | ||
| type=PRECONDITION_FAILED, | ||
| message="Wrong password.", | ||
| ) | ||
| ] | ||
| ) | ||
|
|
||
| async def post_update_hook(self, old_resource, updated_resource): | ||
| if old_resource.password != updated_resource.password: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.