diff --git a/config/configtemplate.json b/config/configtemplate.json
index b60a98d..80f343d 100644
--- a/config/configtemplate.json
+++ b/config/configtemplate.json
@@ -21,6 +21,7 @@
},
"session": {
"session_expiry_seconds": 86400,
+ "session_refresh_seconds": 43200,
"max_session_count": 5,
"auto_cookie": true,
"auto_cookie_name": "session",
diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md
index 4186754..78d1a62 100644
--- a/docs/configuration/configuration.md
+++ b/docs/configuration/configuration.md
@@ -41,6 +41,7 @@ Make sure that all parameters are set correctly before starting the service.
| Parameter | Description |
|------------|-------------|
| `session.session_expiry_seconds` | **Datatype:** Integer
**Default:** `86400`
The time in seconds until a login session expires. Expires on Client (Browser) and on the Server (Database). |
+| `session.session_refresh_seconds` | **Datatype:** Integer
**Default:** `43200`
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
**Default:** `5`
Maximum amount of sessions for one User. |
| `session.auto_cookie` | **Datatype:** Boolean
**Default:** `true`
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
**Default:** `"session"`
The name of the cookie which will be set by the API. |
diff --git a/src/api/dependencies/authenticated.py b/src/api/dependencies/authenticated.py
index 6632bbf..f5cc263 100644
--- a/src/api/dependencies/authenticated.py
+++ b/src/api/dependencies/authenticated.py
@@ -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)
):
@@ -24,7 +28,7 @@ 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)
@@ -32,6 +36,7 @@ async def get_pub_user_dep(
if not user:
logging.debug("No user for session found")
raise HTTPException(status_code=401)
+ session_token_used(session)
return user
@@ -54,7 +59,7 @@ 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)
@@ -62,6 +67,7 @@ async def get_user_dep(
if not user:
logging.debug("No user for session found")
raise HTTPException(status_code=401)
+ session_token_used(session)
return user
@@ -84,7 +90,7 @@ 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)
@@ -92,4 +98,5 @@ async def get_dangerous_user_dep(
if not user:
logging.debug("No user for session found")
raise HTTPException(status_code=401)
+ session_token_used(session)
return user
diff --git a/src/api/helpers/extension_loader.py b/src/api/helpers/extension_loader.py
index 0e0328a..14eeb56 100644
--- a/src/api/helpers/extension_loader.py
+++ b/src/api/helpers/extension_loader.py
@@ -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)
diff --git a/src/crud/sessions.py b/src/crud/sessions.py
index 77b0afe..eba03cc 100644
--- a/src/crud/sessions.py
+++ b/src/crud/sessions.py
@@ -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()}},
+ )
diff --git a/src/tools/conf/SessionConfig.py b/src/tools/conf/SessionConfig.py
index 93e19a6..fc5d12b 100644
--- a/src/tools/conf/SessionConfig.py
+++ b/src/tools/conf/SessionConfig.py
@@ -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"]
@@ -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(
@@ -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(
diff --git a/src/tools/conf/testing_config.json b/src/tools/conf/testing_config.json
index fe33b68..966f2e4 100644
--- a/src/tools/conf/testing_config.json
+++ b/src/tools/conf/testing_config.json
@@ -21,6 +21,7 @@
},
"session": {
"session_expiry_seconds": 86400,
+ "session_refresh_seconds": 43200,
"max_session_count": 5,
"auto_cookie": true,
"auto_cookie_name": "session",