def get_uuid( principal: Principal, db: Session, tenant_uuid: Optional[UUID], create: bool = True ) -> UUID4: if principal is None: if tenant_uuid is None: raise HTTPException( status_code=400, detail=dumps( { "detail": [ { "loc": ["body", "tenant_uuid"], "msg": "field required", "type": "value_error.missing", } ] } ), headers={"Content-Type": "text/json;charset=\"UTF8\""}, ) elif tenant_uuid is not None and tenant_uuid != UUID4(principal.tenant_uuid): raise HTTPException( status_code=403, detail="Token not valid for tenant_uuid %s" % tenant_uuid ) else: tenant_uuid = UUID4(principal.tenant_uuid) if create and get_tenant_by_uuid(db, str(tenant_uuid)) is None: tenant = schema.TenantCreate(name=str(tenant_uuid), uuid=tenant_uuid) create_tenant(db, principal, tenant) return tenant_uuid
async def __call__( self, credentials: Optional[str], user_db: BaseUserDatabase, ) -> Optional[BaseUserDB]: if credentials is None: return None try: data = jwt.decode( credentials, self.secret, audience=self.token_audience, algorithms=[JWT_ALGORITHM], ) user_id = data.get("user_id") if user_id is None: return None except jwt.PyJWTError: return None try: user_uiid = UUID4(user_id) return await user_db.get(user_uiid) except ValueError: return None
async def __call__(self, credentials: Optional[str], user_db: BaseUserDatabase): if credentials is not None: try: token_uuid = UUID4(credentials) return await user_db.get(token_uuid) except ValueError: return None return None
async def reset_password( request: Request, token: str = Body(...), password: str = Body(...) ): try: data = jwt.decode( token, reset_password_token_secret, audience=RESET_PASSWORD_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM], ) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) try: user_uiid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user = await user_db.get(user_uiid) if user is None or not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) if validate_password: try: await validate_password(password, user) except InvalidPasswordException as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail={ "code": ErrorCode.RESET_PASSWORD_INVALID_PASSWORD, "reason": e.reason, }, ) user.hashed_password = get_password_hash(password) await user_db.update(user) if after_reset_password: await run_handler(after_reset_password, user, request) except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, )
async def activate(request: Request, token: str = Body(...)): try: data = jwt.decode( token, activation_token_secret, audience=ACTIVATE_USER_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM], ) except jwt.exceptions.ExpiredSignatureError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.ACTIVATE_USER_TOKEN_EXPIRED, ) except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.ACTIVATE_USER_BAD_TOKEN, ) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.ACTIVATE_USER_BAD_TOKEN, ) try: user_uuid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.ACTIVATE_USER_BAD_TOKEN, ) user = await user_db.get(user_uuid) if user is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.ACTIVATE_USER_BAD_TOKEN, ) if user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.ACTIVATE_USER_LINK_USED, ) user.is_active = True await user_db.update(user) if after_register: await run_handler(after_register, user, request) return user
async def read_token( self, token: Optional[str], user_manager: BaseUserManager[UserCreate, UserDB]) -> Optional[UserDB]: if token is not None: try: token_uuid = UUID4(token) return await user_manager.get(token_uuid) except ValueError: return None except UserNotExists: return None return None
async def verify(self, token: str, request: Optional[Request] = None) -> models.UD: """ Validate a verification request. Changes the is_verified flag of the user to True. Triggers the on_after_verify handler on success. :param token: The verification token generated by request_verify. :param request: Optional FastAPI request that triggered the operation, defaults to None. :raises InvalidVerifyToken: The token is invalid or expired. :raises UserAlreadyVerified: The user is already verified. :return: The verified user. """ try: data = decode_jwt( token, self.verification_token_secret, [self.verification_token_audience], ) except jwt.PyJWTError: raise InvalidVerifyToken() try: user_id = data["user_id"] email = data["email"] except KeyError: raise InvalidVerifyToken() try: user = await self.get_by_email(email) except UserNotExists: raise InvalidVerifyToken() try: user_uuid = UUID4(user_id) except ValueError: raise InvalidVerifyToken() if user_uuid != user.id: raise InvalidVerifyToken() if user.is_verified: raise UserAlreadyVerified() verified_user = await self._update(user, {"is_verified": True}) await self.on_after_verify(verified_user, request) return verified_user
async def get(cls, request: web.Request): """Get file from storage by UUID.""" try: uuid = UUID4(request.match_info["uuid"]) except ValueError: raise web.HTTPBadRequest app: AioHttpApplication = cast(AioHttpApplication, request.app) conn: Connection query = retrieve_data_by_uuid() async with app.db.acquire() as conn: data = await conn.fetchrow(query, uuid) if not data: raise web.HTTPNotFound return web.Response(body=data["data"], content_type=data["content_type"])
async def get_current_token_data(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) uuid = payload.get("sub") if uuid is None: raise credentials_exception role = payload.get("role") token_data = TokenData(id=UUID4(uuid), role=role) except JWTError: raise credentials_exception return token_data
async def read_token( self, token: Optional[str], user_manager: BaseUserManager[models.UC, models.UD] ) -> Optional[models.UD]: if token is None: return None user_id = await self.redis.get(token) if user_id is None: return None try: user_uiid = UUID4(user_id) return await user_manager.get(user_uiid) except ValueError: return None except UserNotExists: return None
async def reset_password( self, token: str, password: str, request: Optional[Request] = None ) -> models.UD: """ Reset the password of a user. Triggers the on_after_reset_password handler on success. :param token: The token generated by forgot_password. :param password: The new password to set. :param request: Optional FastAPI request that triggered the operation, defaults to None. :raises InvalidResetPasswordToken: The token is invalid or expired. :raises UserInactive: The user is inactive. :raises InvalidPasswordException: The password is invalid. :return: The user with updated password. """ try: data = decode_jwt( token, self.reset_password_token_secret, [self.reset_password_token_audience], ) except jwt.PyJWTError: raise InvalidResetPasswordToken() try: user_id = data["user_id"] except KeyError: raise InvalidResetPasswordToken() try: user_uuid = UUID4(user_id) except ValueError: raise InvalidResetPasswordToken() user = await self.get(user_uuid) if not user.is_active: raise UserInactive() updated_user = await self._update(user, {"password": password}) await self.on_after_reset_password(user, request) return updated_user
async def reset_password(_: Response, formdata: ResetPasswordVM): token = formdata.token password = formdata.password try: data = jwt.decode(token, s.SECRET_KEY_EMAIL, audience=RESET_PASSWORD_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM]) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) try: user_uuid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user = await userdb.get(user_uuid) if user is None or not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user.hashed_password = get_password_hash(password) # Use UserDB in order to remove the extra attributes generated by UserDBComplete user = UserDB(**user.dict()) await userdb.update(user) return True except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, )
async def read_token( self, token: Optional[str], user_manager: BaseUserManager[models.UC, models.UD] ) -> Optional[models.UD]: if token is None: return None try: data = decode_jwt(token, self.secret, self.token_audience) user_id = data.get("user_id") if user_id is None: return None except jwt.PyJWTError: return None try: user_uiid = UUID4(user_id) return await user_manager.get(user_uiid) except ValueError: return None except UserNotExists: return None
async def reset_password(token: str = Body(...), password: str = Body(...)): try: data = jwt.decode( token, reset_password_token_secret, audience=RESET_PASSWORD_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM], ) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) try: user_uiid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user = await user_db.get(user_uiid) if user is None or not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user.hashed_password = get_password_hash(password) await user_db.update(user) except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, )
async def test_valid_body_correct_token_produced( self, test_app_client: httpx.AsyncClient, after_register, activation_callback): json = { "email": "*****@*****.**", "password": "******", } response = await test_app_client.post("/register", json=json) assert response.status_code == status.HTTP_201_CREATED assert after_register.called is False assert activation_callback.called is True token = activation_callback.call_args[0][1] data = jwt.decode( token, activation_token_secret, audience=ACTIVATE_USER_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM], ) user_id = data.get("user_id") user_uuid = UUID4(user_id) created_user = activation_callback.call_args[0][0] assert user_uuid == created_user.id
async def test_not_existing_user(self, user_manager: UserManagerMock): with pytest.raises(UserNotExists): await user_manager.get( UUID4("d35d213e-f3d8-4f08-954a-7e0d1bea286f"))
async def verify(request: Request, token: str = Body(..., embed=True)): try: data = jwt.decode( token, verification_token_secret, audience=VERIFY_USER_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM], ) except jwt.exceptions.ExpiredSignatureError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_TOKEN_EXPIRED, ) except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_BAD_TOKEN, ) user_id = data.get("user_id") email = cast(EmailStr, data.get("email")) if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_BAD_TOKEN, ) try: user_check = await get_user(email) except UserNotExists: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_BAD_TOKEN, ) try: user_uuid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_BAD_TOKEN, ) if user_check.id != user_uuid: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_BAD_TOKEN, ) try: user = await verify_user(user_check) except UserAlreadyVerified: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.VERIFY_USER_ALREADY_VERIFIED, ) if after_verification: await run_handler(after_verification, user, request) return user
from typing import Optional from pydantic import UUID4 from aggreagates.reservations.domain.repository import ResourceRepository from aggreagates.reservations.domain.resource import Resource, ResourceId initial_resource = Resource( resource_id=ResourceId(id=UUID4("0c51b998-e97b-4e8d-9df1-116e2c9eb384")), reservations=[] ) class InMemoryResourceRepository(ResourceRepository): def __init__(self): self.data = { initial_resource.resource_id: initial_resource } def get(self, resource_id: ResourceId) -> Optional[Resource]: return self.data.get(resource_id) def save(self, resource: Resource) -> None: self.data[resource.resource_id] = resource
def from_string(cls, id: str): return cls(id=UUID4(id))