Skip to content

Commit fc40a0c

Browse files
committed
refactor names and product check
1 parent 095fa5d commit fc40a0c

File tree

4 files changed

+26
-17
lines changed

4 files changed

+26
-17
lines changed

api/specs/web-server/_auth.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,16 +178,15 @@ async def initiate_reset_password(_body: ResetPasswordBody): ...
178178
@router.post(
179179
"/auth/reset-password/{code}",
180180
response_model=Envelope[Log],
181-
operation_id="auth_reset_password_allowed",
181+
operation_id="complete_reset_password",
182182
responses={
183183
status.HTTP_401_UNAUTHORIZED: {
184184
"model": EnvelopedError,
185-
"description": "unauthorized reset due to invalid token code",
185+
"description": "Invalid token code",
186186
}
187187
},
188188
)
189-
async def reset_password_allowed(code: str, _body: ResetPasswordConfirmation):
190-
"""changes password using a token code without being logged in"""
189+
async def complete_reset_password(code: str, _body: ResetPasswordConfirmation): ...
191190

192191

193192
@router.post(

services/web/server/src/simcore_service_webserver/login/handlers_change.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from ..products import products_web
1717
from ..products.models import Product
1818
from ..security.api import check_password, encrypt_password
19+
from ..users import api as users_service
1920
from ..utils import HOUR
2021
from ..utils_rate_limiting import global_rate_limit_route
2122
from ._confirmation import is_confirmation_valid, make_confirmation_link
@@ -52,7 +53,7 @@ class ResetPasswordBody(InputSchema):
5253
@routes.post(f"/{API_VTAG}/auth/reset-password", name="initiate_reset_password")
5354
@global_rate_limit_route(number_of_requests=10, interval_seconds=HOUR)
5455
async def initiate_reset_password(request: web.Request):
55-
"""First of the "Two-Step Action Confirmation pattern"
56+
"""First of the "Two-Step Action Confirmation pattern": initiate_reset_password + complete_reset_password(code)
5657
5758
1. confirm user exists
5859
2. check user status
@@ -76,7 +77,7 @@ async def initiate_reset_password(request: web.Request):
7677
# with a given email or username.
7778
response = flash_response(MSG_EMAIL_SENT.format(email=request_body.email), "INFO")
7879

79-
# check user exists
80+
# CHECK user exists
8081
user = await db.get_user({"email": request_body.email})
8182
if not user:
8283
_logger.warning(
@@ -86,7 +87,7 @@ async def initiate_reset_password(request: web.Request):
8687
)
8788
return response
8889

89-
# check user state
90+
# CHECK user state
9091
try:
9192
validate_user_status(user=dict(user), support_email=product.support_email)
9293
except web.HTTPError as err:
@@ -99,9 +100,16 @@ async def initiate_reset_password(request: web.Request):
99100

100101
assert user["status"] == ACTIVE # nosec
101102
assert user["email"] == request_body.email # nosec
103+
assert isinstance(user["id"], int) # nosec
102104

103-
# check access to product
104-
# TODO:
105+
# CHECK access to product
106+
if not await users_service.is_user_in_product(
107+
request.app, user_id=user["id"], product_name=product.name
108+
):
109+
_logger.warning(
110+
"Password rest requested for a registered user but wihtout access to product"
111+
)
112+
return response
105113

106114
if await is_confirmation_valid(cfg, db, user, action=RESET_PASSWORD):
107115
_logger.warning(
@@ -111,10 +119,11 @@ async def initiate_reset_password(request: web.Request):
111119
# delete previous and resend new?
112120
return response
113121

114-
# TODO: create confirmation code,
115-
confirmation = await db.create_confirmation(user["id"], action=RESET_PASSWORD)
116-
link = make_confirmation_link(request, confirmation)
117122
try:
123+
# Produce a link so that the front-end can hit `complete_reset_password`
124+
confirmation = await db.create_confirmation(user["id"], action=RESET_PASSWORD)
125+
link = make_confirmation_link(request, confirmation)
126+
118127
# primary reset email with a URL and the normal instructions.
119128
await send_email_from_template(
120129
request,

services/web/server/src/simcore_service_webserver/login/handlers_confirmation.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,12 @@ class ResetPasswordConfirmation(InputSchema):
273273
_password_confirm_match = field_validator("confirm")(check_confirm_password_match)
274274

275275

276-
@routes.post("/v0/auth/reset-password/{code}", name="auth_reset_password_allowed")
277-
async def reset_password(request: web.Request):
278-
"""Changes password using a token code without being logged in
276+
@routes.post("/v0/auth/reset-password/{code}", name="complete_reset_password")
277+
async def complete_reset_password(request: web.Request):
278+
"""Last of the "Two-Step Action Confirmation pattern": initiate_reset_password + complete_reset_password(code)
279279
280-
Code is provided via email by calling first submit_request_to_reset_password
280+
- Changes password using a token code without login
281+
- Code is provided via email by calling first initiate_reset_password
281282
"""
282283
db: AsyncpgStorage = get_plugin_storage(request.app)
283284
cfg: LoginOptions = get_plugin_options(request.app)

services/web/server/tests/unit/with_dbs/03/login/test_login_reset_password.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ async def test_reset_and_confirm(
184184
)
185185

186186
# api/specs/webserver/v0/components/schemas/auth.yaml#/ResetPasswordForm
187-
reset_allowed_url = client.app.router["auth_reset_password_allowed"].url_for(
187+
reset_allowed_url = client.app.router["complete_reset_password"].url_for(
188188
code=code
189189
)
190190
new_password = generate_password(10)

0 commit comments

Comments
 (0)