Fix a bug with validate returning 401 when a session was refreshed. Simplify & cleanup.
This commit is contained in:
@@ -39,21 +39,6 @@ def get_reset(token: str) -> "ResetToken":
|
|||||||
raise ValueError("This authentication link is no longer valid.")
|
raise ValueError("This authentication link is no longer valid.")
|
||||||
|
|
||||||
|
|
||||||
def refresh_session_token(token: str, *, ip: str, user_agent: str):
|
|
||||||
"""Refresh a session extending its expiry."""
|
|
||||||
session_record = db.data().sessions.get(token)
|
|
||||||
if not session_record:
|
|
||||||
raise ValueError("Session not found or expired")
|
|
||||||
updated = db.update_session(
|
|
||||||
token,
|
|
||||||
ip=ip,
|
|
||||||
user_agent=user_agent,
|
|
||||||
expiry=expires(),
|
|
||||||
)
|
|
||||||
if not updated:
|
|
||||||
raise ValueError("Session not found or expired")
|
|
||||||
|
|
||||||
|
|
||||||
def delete_credential(credential_uuid: UUID, auth: str, host: str | None = None):
|
def delete_credential(credential_uuid: UUID, auth: str, host: str | None = None):
|
||||||
"""Delete a specific credential for the current user."""
|
"""Delete a specific credential for the current user."""
|
||||||
ctx = db.data().session_ctx(auth, hostutil.normalize_host(host))
|
ctx = db.data().session_ctx(auth, hostutil.normalize_host(host))
|
||||||
|
|||||||
+27
-36
@@ -14,11 +14,7 @@ from fastapi.responses import JSONResponse
|
|||||||
from fastapi.security import HTTPBearer
|
from fastapi.security import HTTPBearer
|
||||||
|
|
||||||
from paskia import db
|
from paskia import db
|
||||||
from paskia.authsession import (
|
from paskia.authsession import EXPIRES, expires, get_reset
|
||||||
EXPIRES,
|
|
||||||
get_reset,
|
|
||||||
refresh_session_token,
|
|
||||||
)
|
|
||||||
from paskia.fastapi import authz, session, user
|
from paskia.fastapi import authz, session, user
|
||||||
from paskia.fastapi.response import MsgspecResponse
|
from paskia.fastapi.response import MsgspecResponse
|
||||||
from paskia.fastapi.session import AUTH_COOKIE, AUTH_COOKIE_NAME
|
from paskia.fastapi.session import AUTH_COOKIE, AUTH_COOKIE_NAME
|
||||||
@@ -93,19 +89,14 @@ async def validate_token(
|
|||||||
if auth:
|
if auth:
|
||||||
consumed = EXPIRES - (ctx.session.expiry - datetime.now(UTC))
|
consumed = EXPIRES - (ctx.session.expiry - datetime.now(UTC))
|
||||||
if not timedelta(0) < consumed < _REFRESH_INTERVAL:
|
if not timedelta(0) < consumed < _REFRESH_INTERVAL:
|
||||||
try:
|
db.update_session(
|
||||||
refresh_session_token(
|
auth,
|
||||||
auth,
|
ip=request.client.host if request.client else "",
|
||||||
ip=request.client.host if request.client else "",
|
user_agent=request.headers.get("user-agent") or "",
|
||||||
user_agent=request.headers.get("user-agent") or "",
|
expiry=expires(),
|
||||||
)
|
)
|
||||||
session.set_session_cookie(response, auth)
|
session.set_session_cookie(response, auth)
|
||||||
renewed = True
|
renewed = True
|
||||||
except ValueError:
|
|
||||||
# Session disappeared, e.g. due to concurrent logout; global handler will clear
|
|
||||||
raise authz.AuthException(
|
|
||||||
status_code=401, detail="Session expired", mode="login"
|
|
||||||
)
|
|
||||||
return MsgspecResponse(
|
return MsgspecResponse(
|
||||||
{
|
{
|
||||||
"valid": True,
|
"valid": True,
|
||||||
@@ -115,24 +106,6 @@ async def validate_token(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/token-info")
|
|
||||||
async def token_info(credentials=Depends(bearer_auth)):
|
|
||||||
"""Get reset/device-add token info. Pass token via Bearer header."""
|
|
||||||
token = credentials.credentials
|
|
||||||
if not passphrase.is_well_formed(token):
|
|
||||||
raise HTTPException(400, "Invalid token format")
|
|
||||||
try:
|
|
||||||
reset_token = get_reset(token)
|
|
||||||
except ValueError as e:
|
|
||||||
raise HTTPException(401, str(e))
|
|
||||||
|
|
||||||
u = reset_token.user
|
|
||||||
return {
|
|
||||||
"token_type": reset_token.token_type,
|
|
||||||
"display_name": u.display_name,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/forward")
|
@app.get("/forward")
|
||||||
async def forward_authentication(
|
async def forward_authentication(
|
||||||
request: Request,
|
request: Request,
|
||||||
@@ -248,6 +221,24 @@ async def api_user_info(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/token-info")
|
||||||
|
async def token_info(credentials=Depends(bearer_auth)):
|
||||||
|
"""Get reset/device-add token info. Pass token via Bearer header."""
|
||||||
|
token = credentials.credentials
|
||||||
|
if not passphrase.is_well_formed(token):
|
||||||
|
raise HTTPException(400, "Invalid token format")
|
||||||
|
try:
|
||||||
|
reset_token = get_reset(token)
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(401, str(e))
|
||||||
|
|
||||||
|
u = reset_token.user
|
||||||
|
return {
|
||||||
|
"token_type": reset_token.token_type,
|
||||||
|
"display_name": u.display_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/logout")
|
@app.post("/logout")
|
||||||
async def api_logout(request: Request, response: Response, auth=AUTH_COOKIE):
|
async def api_logout(request: Request, response: Response, auth=AUTH_COOKIE):
|
||||||
if not auth:
|
if not auth:
|
||||||
|
|||||||
Reference in New Issue
Block a user