Skip to content

Commit

Permalink
Session Refreshing
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnGrubba committed Aug 12, 2024
1 parent 03f300d commit 2ccfaac
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 5 deletions.
1 change: 1 addition & 0 deletions config/configtemplate.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"session": {
"session_expiry_seconds": 86400,
"session_refresh_seconds": 43200,
"max_session_count": 5,
"auto_cookie": true,
"auto_cookie_name": "session",
Expand Down
1 change: 1 addition & 0 deletions docs/configuration/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Make sure that all parameters are set correctly before starting the service.
| Parameter | Description |
|------------|-------------|
| `session.session_expiry_seconds` | **Datatype:** Integer <br> **Default:** `86400` <br> The time in seconds until a login session expires. Expires on Client (Browser) and on the Server (Database). |
| `session.session_refresh_seconds` | **Datatype:** Integer <br> **Default:** `43200` <br> The session get's automatically extended if user performs **any authentication requiring action** within session_refresh_seconds (43200) before expiry. Be careful with this parameter, because setting it too close to session_expiry_seconds, may cause unwanted server and database load due to more frequent session expiry update actions. |
| `session.max_session_count` | **Datatype:** Integer <br> **Default:** `5` <br> Maximum amount of sessions for one User. |
| `session.auto_cookie` | **Datatype:** Boolean <br> **Default:** `true` <br> Specifies if the API should automatically return a `Set-Cookie` header to potentially automatically set the Session Token for the client. May simplify upcoming requests to this API. |
| `session.auto_cookie_name` | **Datatype:** String <br> **Default:** `"session"` <br> The name of the cookie which will be set by the API. |
Expand Down
15 changes: 11 additions & 4 deletions src/api/dependencies/authenticated.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from fastapi import HTTPException, Cookie
from tools import SessionConfig
from tools import sessions_collection
from crud.user import get_public_user, get_user, get_dangerous_user
from crud.sessions import extend_session, get_session
import logging


def session_token_used(session: str):
extend_session(session)


async def get_pub_user_dep(
session_token: str = Cookie(default=None, alias=SessionConfig.auto_cookie_name)
):
Expand All @@ -24,14 +28,15 @@ async def get_pub_user_dep(
if not session_token:
logging.debug("No session token")
raise HTTPException(status_code=401)
session = sessions_collection.find_one({"session_token": session_token})
session = get_session(session_token)
if not session:
logging.debug("No session found")
raise HTTPException(status_code=401)
user = get_public_user(session["user_id"])
if not user:
logging.debug("No user for session found")
raise HTTPException(status_code=401)
session_token_used(session)
return user


Expand All @@ -54,14 +59,15 @@ async def get_user_dep(
if not session_token:
logging.debug("No session token")
raise HTTPException(status_code=401)
session = sessions_collection.find_one({"session_token": session_token})
session = get_session(session_token)
if not session:
logging.debug("No session found")
raise HTTPException(status_code=401)
user = get_user(session["user_id"])
if not user:
logging.debug("No user for session found")
raise HTTPException(status_code=401)
session_token_used(session)
return user


Expand All @@ -84,12 +90,13 @@ async def get_dangerous_user_dep(
if not session_token:
logging.debug("No session token")
raise HTTPException(status_code=401)
session = sessions_collection.find_one({"session_token": session_token})
session = get_session(session_token)
if not session:
logging.debug("No session found")
raise HTTPException(status_code=401)
user = get_dangerous_user(session["user_id"])
if not user:
logging.debug("No user for session found")
raise HTTPException(status_code=401)
session_token_used(session)
return user
2 changes: 1 addition & 1 deletion src/api/helpers/extension_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def load_extensions(app: FastAPI):
readme_file = None
try:
readme_file = open(os.path.join(item_path, "README.md"), "r").read()
except:
except FileNotFoundError:
logger.error(f"Extension {item} is missing README.md")
spec = importlib.util.spec_from_file_location(item, init_file)
module = importlib.util.module_from_spec(spec)
Expand Down
22 changes: 22 additions & 0 deletions src/crud/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,25 @@ def count_sessions() -> int:
int: Amount of Sessions
"""
return sessions_collection.count_documents({})


def extend_session(session: dict) -> None:
"""
Extend the session expiration time, depending on configuration.
Args:
session_token (str): Session Token
"""
expiry = session["createdAt"] + datetime.timedelta(
seconds=SessionConfig.session_expiry_seconds
)

start_extending_period = expiry - datetime.timedelta(
seconds=SessionConfig.session_refresh_seconds
)

if datetime.datetime.now() >= start_extending_period:
sessions_collection.update_one(
{"session_token": session["session_token"]},
{"$set": {"createdAt": datetime.datetime.now()}},
)
17 changes: 17 additions & 0 deletions src/tools/conf/SessionConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class SessionConfig:
session_expiry_seconds: int = config["session"]["session_expiry_seconds"]
session_refresh_seconds: int = config["session"]["session_refresh_seconds"]
max_session_count: int = config["session"]["max_session_count"]
auto_cookie: bool = config["session"]["auto_cookie"]
auto_cookie_name: str = config["session"]["auto_cookie_name"]
Expand All @@ -17,6 +18,12 @@ def validate_types(self) -> bool:
type(self.session_expiry_seconds)
)
)
if not isinstance(self.session_refresh_seconds, int):
raise ValueError(
"session.session_refresh_seconds must be an integer (got type {})".format(
type(self.session_refresh_seconds)
)
)
if not isinstance(self.max_session_count, int):
raise ValueError(
"session.max_session_count must be an integer (got type {})".format(
Expand Down Expand Up @@ -56,6 +63,16 @@ def validate_values(self) -> bool:
self.session_expiry_seconds
)
)
if not self.session_refresh_seconds > 0:
raise ValueError(
"session.session_refresh_seconds must be a positive integer (got {})".format(
self.session_refresh_seconds
)
)
if self.session_refresh_seconds > self.session_expiry_seconds:
raise ValueError(
"session.session_refresh_seconds must be less or equal than session.session_expiry_seconds"
)
if not self.max_session_count > 0:
raise ValueError(
"session.max_session_count must be a positive integer (got {})".format(
Expand Down
1 change: 1 addition & 0 deletions src/tools/conf/testing_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"session": {
"session_expiry_seconds": 86400,
"session_refresh_seconds": 43200,
"max_session_count": 5,
"auto_cookie": true,
"auto_cookie_name": "session",
Expand Down

0 comments on commit 2ccfaac

Please sign in to comment.