diff --git a/Taskfile.yml b/Taskfile.yml index 8f1731fe9..d5c0c8951 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,7 +5,7 @@ tasks: upload-kibana-objs: desc: Upload dashboards to Kibana server cmds: - - curl -X POST localhost:5601/api/saved_objects/_import -H "kbn-xsrf: true" --form file=@tdrs-backend/tdpservice/search_indexes/kibana_saved_objs.ndjson + - 'curl -X POST localhost:5601/api/saved_objects/_import -H "kbn-xsrf: true" --form file=@tdrs-backend/tdpservice/search_indexes/kibana_saved_objs.ndjson' create-network: desc: Create the external network diff --git a/tdrs-backend/docs/session-management.md b/tdrs-backend/docs/session-management.md index e4f0c1831..6c079efe8 100644 --- a/tdrs-backend/docs/session-management.md +++ b/tdrs-backend/docs/session-management.md @@ -11,7 +11,7 @@ When the user logs in, they will receive an HttpOnly cookie with no `Expires=` s SESSION_EXPIRE_AT_BROWSER_CLOSE=True ``` -The cookie itself contains a `sessionid` reference to a Django-managed session. The session expiration is set to the same expiration of the login.gov-provided jwt, **15 minutes**. +The cookie itself contains a `sessionid` reference to a Django-managed session. By deafult, the session expiration is set to the same expiration of the login.gov-provided jwt, **15 minutes**. Since `sessionid` is being signed when created, it not possible to update the expiry without decoding and recreating the signature, so the session expires even though the cookie is being extended with every request. Thus, in order to overcome this shortcoming, a longer expiry is being assigned to `sessionid` using a new variable `SIGNED_COOKIE_EXPIRES` in common settings. This is managed in `tdrs-backend/tdpservice/settings/common.py` with the following setting: ```python diff --git a/tdrs-backend/tdpservice/core/custom_session_engine.py b/tdrs-backend/tdpservice/core/custom_session_engine.py new file mode 100644 index 000000000..70f397a52 --- /dev/null +++ b/tdrs-backend/tdpservice/core/custom_session_engine.py @@ -0,0 +1,34 @@ +"""Custom session engine for TDP.""" + +from django.contrib.sessions.backends import signed_cookies +from django.core import signing +import datetime +from django.conf import settings + +class SessionStore(signed_cookies.SessionStore): + """Custom session engine for TDP.""" + + def __init__(self, session_key=None): + """Initialize the custom session engine.""" + super().__init__(session_key) + + def load(self): + """Load the session data from the database.""" + """ + Load the data from the key itself instead of fetching from some + external data store. Opposite of _get_session_key(), raise BadSignature + if signature fails. + """ + + try: + return signing.loads( + self.session_key, + serializer=self.serializer, + # This doesn't handle non-default expiry dates, see #19201 + max_age=datetime.timedelta(seconds=settings.SIGNED_COOKIE_EXPIRES), + salt="django.contrib.sessions.backends.signed_cookies", + ) + except Exception: + # BadSignature, ValueError, or unpickling exceptions. If any of + # these happen, reset the session. + return {} diff --git a/tdrs-backend/tdpservice/data_files/admin/admin.py b/tdrs-backend/tdpservice/data_files/admin/admin.py index 51ddfd1d9..4c9fce07a 100644 --- a/tdrs-backend/tdpservice/data_files/admin/admin.py +++ b/tdrs-backend/tdpservice/data_files/admin/admin.py @@ -1,7 +1,6 @@ """Admin class for DataFile objects.""" from django.contrib import admin from tdpservice.core.utils import ReadOnlyAdminMixin -# from tdpservice.core.filters import custom_filter_title from tdpservice.data_files.models import DataFile, LegacyFileTransfer from tdpservice.parsers.models import DataFileSummary, ParserError from tdpservice.data_files.admin.filters import LatestReparseEvent, VersionFilter diff --git a/tdrs-backend/tdpservice/settings/common.py b/tdrs-backend/tdpservice/settings/common.py index ba936b545..6f4e35353 100644 --- a/tdrs-backend/tdpservice/settings/common.py +++ b/tdrs-backend/tdpservice/settings/common.py @@ -281,10 +281,11 @@ class Common(Configuration): ) # Sessions - SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" + SESSION_ENGINE = "tdpservice.core.custom_session_engine" + SIGNED_COOKIE_EXPIRES = 60 * 60 * 12 # 12 hours SESSION_COOKIE_HTTPONLY = True - SESSION_EXPIRE_AT_BROWSER_CLOSE = True - SESSION_COOKIE_AGE = 15 * 60 # 15 minutes + SESSION_SAVE_EVERY_REQUEST = True + SESSION_COOKIE_AGE = 60 * 30 # 30 minutes # The CSRF token Cookie holds no security benefits when confined to HttpOnly. # Setting this to false to allow the frontend to include it in the header # of API POST calls to prevent false negative authorization errors.