Forcibly destroy existing session on logout.

To comply with security guidelines, we need to destroy the session when
a user logs out. This means that the session's key in the Redis cache
needs to be deleted. Flask expects to _always_ have a session object. If
the current session object does not exist in the Redis cache, Flask will
reserialize and store it at the end of the request. In order for
session deletion to work, we need to delete the key for the existing
session and then replace the session object with a new, empty one.

This also updates the SessionLimiter class so that the session prefix is
configurable.
This commit is contained in:
dandds
2020-01-19 16:05:54 -05:00
parent 0fa4fd2304
commit 944c5d3c9f
6 changed files with 63 additions and 15 deletions

View File

@@ -1,4 +1,13 @@
from flask import g, redirect, url_for, session, request, current_app as app
from flask import (
g,
redirect,
url_for,
session,
request,
current_app as app,
_request_ctx_stack as request_ctx_stack,
)
from werkzeug.datastructures import ImmutableTypeConversionDict
from atst.domain.users import Users
@@ -56,12 +65,26 @@ def get_last_login():
return session.get("user_id") and session.get("last_login")
def _nullify_session(session):
session_key = f"{app.config.get('SESSION_KEY_PREFIX')}{session.sid}"
app.redis.delete(session_key)
request.cookies = ImmutableTypeConversionDict()
request_ctx_stack.top.session = app.session_interface.open_session(app, request)
def _current_dod_id():
return g.current_user.dod_id if session.get("user_id") else None
def logout():
if session.get("user_id"): # pragma: no branch
dod_id = g.current_user.dod_id
del session["user_id"]
del session["last_login"]
dod_id = _current_dod_id()
_nullify_session(session)
if dod_id:
app.logger.info(f"user with EDIPI {dod_id} has logged out")
else:
app.logger.info("unauthenticated user has logged out")
def _unprotected_route(request):

View File

@@ -4,6 +4,7 @@ from atst.domain.users import Users
class SessionLimiter(object):
def __init__(self, config, session, redis):
self.limit_logins = config["LIMIT_CONCURRENT_SESSIONS"]
self.session_prefix = config.get("SESSION_KEY_PREFIX", "session:")
self.session = session
self.redis = redis
@@ -16,4 +17,4 @@ class SessionLimiter(object):
Users.update_last_session_id(user, session_id)
def _delete_session(self, session_id):
self.redis.delete("session:{}".format(session_id))
self.redis.delete(f"{self.session_prefix}{session_id}")