mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
change(python): rework session timing
Previously, we were just relying on the cookie expiration for sessions to expire. We were not cleaning up Session records either. Rework timing to depend on an AURREMEMBER cookie which is now emitted on login during BasicAuthBackend processing. If the SID does still have a session but it's expired, we now delete the session record before returning. Otherwise, we update the session's LastUpdateTS to the current time. In addition, stored the unauthenticated result value in a variable to reduce redundancy. Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
f8bef16d32
commit
8501bba0ac
5 changed files with 50 additions and 24 deletions
|
@ -7,7 +7,6 @@ import fastapi
|
|||
|
||||
from fastapi import HTTPException
|
||||
from fastapi.responses import RedirectResponse
|
||||
from sqlalchemy import and_
|
||||
from starlette.authentication import AuthCredentials, AuthenticationBackend
|
||||
from starlette.requests import HTTPConnection
|
||||
|
||||
|
@ -97,18 +96,27 @@ class AnonymousUser:
|
|||
|
||||
class BasicAuthBackend(AuthenticationBackend):
|
||||
async def authenticate(self, conn: HTTPConnection):
|
||||
unauthenticated = (None, AnonymousUser())
|
||||
sid = conn.cookies.get("AURSID")
|
||||
if not sid:
|
||||
return (None, AnonymousUser())
|
||||
return unauthenticated
|
||||
|
||||
now_ts = datetime.utcnow().timestamp()
|
||||
record = db.query(Session).filter(
|
||||
and_(Session.SessionID == sid,
|
||||
Session.LastUpdateTS >= now_ts)).first()
|
||||
timeout = aurweb.config.getint("options", "login_timeout")
|
||||
remembered = ("AURREMEMBER" in conn.cookies
|
||||
and bool(conn.cookies.get("AURREMEMBER")))
|
||||
if remembered:
|
||||
timeout = aurweb.config.getint("options",
|
||||
"persistent_cookie_timeout")
|
||||
|
||||
# If no session with sid and a LastUpdateTS now or later exists.
|
||||
now_ts = int(datetime.utcnow().timestamp())
|
||||
record = db.query(Session).filter(Session.SessionID == sid).first()
|
||||
if not record:
|
||||
return (None, AnonymousUser())
|
||||
return unauthenticated
|
||||
elif record.LastUpdateTS < (now_ts - timeout):
|
||||
with db.begin():
|
||||
db.delete_all([record])
|
||||
return unauthenticated
|
||||
|
||||
# At this point, we cannot have an invalid user if the record
|
||||
# exists, due to ForeignKey constraints in the schema upheld
|
||||
|
|
|
@ -123,10 +123,6 @@ class User(Base):
|
|||
for i in range(tries):
|
||||
exc = None
|
||||
now_ts = datetime.utcnow().timestamp()
|
||||
session_ts = now_ts + (
|
||||
session_time if session_time
|
||||
else aurweb.config.getint("options", "login_timeout")
|
||||
)
|
||||
try:
|
||||
with db.begin():
|
||||
self.LastLogin = now_ts
|
||||
|
@ -135,12 +131,12 @@ class User(Base):
|
|||
sid = generate_unique_sid()
|
||||
self.session = db.create(Session, User=self,
|
||||
SessionID=sid,
|
||||
LastUpdateTS=session_ts)
|
||||
LastUpdateTS=now_ts)
|
||||
else:
|
||||
last_updated = self.session.LastUpdateTS
|
||||
if last_updated and last_updated < now_ts:
|
||||
self.session.SessionID = generate_unique_sid()
|
||||
self.session.LastUpdateTS = session_ts
|
||||
self.session.LastUpdateTS = now_ts
|
||||
break
|
||||
except IntegrityError as exc_:
|
||||
exc = exc_
|
||||
|
|
|
@ -73,6 +73,10 @@ async def login_post(request: Request,
|
|||
response.set_cookie("AURLANG", user.LangPreference,
|
||||
secure=secure, httponly=secure,
|
||||
samesite=cookies.samesite())
|
||||
response.set_cookie("AURREMEMBER", remember_me,
|
||||
expires=expires_at,
|
||||
secure=secure, httponly=secure,
|
||||
samesite=cookies.samesite())
|
||||
return response
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue