mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-11 10:28:41 -04:00
Ensure that the session is logged out server side, not just client side.
Anytime a user clicks "sign out" we should be signing them out server side as well. This can be accomplished by setting the Users.current_session_id = null. I found that the method User.logged_in_elsewhere doesn't need to check if the current_session_id is None. The current_session_ids in the cookie and db (redis or postgres) then the user should be forced to log in again.
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
from flask import redirect, session, url_for
|
from flask import redirect, session, url_for
|
||||||
from flask_login import logout_user
|
from flask_login import current_user, logout_user
|
||||||
|
|
||||||
from app.main import main
|
from app.main import main
|
||||||
|
|
||||||
|
|
||||||
@main.route('/sign-out', methods=(['GET']))
|
@main.route('/sign-out', methods=(['GET']))
|
||||||
def sign_out():
|
def sign_out():
|
||||||
|
current_user.sign_out()
|
||||||
session.clear()
|
session.clear()
|
||||||
logout_user()
|
logout_user()
|
||||||
return redirect(url_for('main.index'))
|
return redirect(url_for('main.index'))
|
||||||
|
|||||||
+5
-2
@@ -127,8 +127,7 @@ class User(JSONModel, UserMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def logged_in_elsewhere(self):
|
def logged_in_elsewhere(self):
|
||||||
# if the current user (ie: db object) has no session, they've never logged in before
|
return session.get('current_session_id') != self.current_session_id
|
||||||
return self.current_session_id is not None and session.get('current_session_id') != self.current_session_id
|
|
||||||
|
|
||||||
def activate(self):
|
def activate(self):
|
||||||
if self.state == 'pending':
|
if self.state == 'pending':
|
||||||
@@ -154,6 +153,10 @@ class User(JSONModel, UserMixin):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def sign_out(self):
|
||||||
|
# Update the db so the server also knows the user is logged out.
|
||||||
|
return self.update(current_session_id=None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sms_auth(self):
|
def sms_auth(self):
|
||||||
return self.auth_type == 'sms_auth'
|
return self.auth_type == 'sms_auth'
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ ALLOWED_ATTRIBUTES = {
|
|||||||
'email_address',
|
'email_address',
|
||||||
'mobile_number',
|
'mobile_number',
|
||||||
'auth_type',
|
'auth_type',
|
||||||
'updated_by'
|
'updated_by',
|
||||||
|
'current_session_id'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ def test_doesnt_redirect_to_sign_in_if_no_session_info(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('db_sess_id, cookie_sess_id', [
|
@pytest.mark.parametrize('db_sess_id, cookie_sess_id', [
|
||||||
pytest.param(None, None, marks=pytest.mark.xfail), # OK - not used notify since browser signout was implemented
|
(None, None),
|
||||||
|
|
||||||
(uuid.UUID(int=1), None), # BAD - has used other browsers before but this is a brand new browser with no cookie
|
(uuid.UUID(int=1), None), # BAD - has used other browsers before but this is a brand new browser with no cookie
|
||||||
(uuid.UUID(int=1), uuid.UUID(int=2)), # BAD - this person has just signed in on a different browser
|
(uuid.UUID(int=1), uuid.UUID(int=2)), # BAD - this person has just signed in on a different browser
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ from tests.conftest import SERVICE_ONE_ID
|
|||||||
|
|
||||||
|
|
||||||
def test_render_sign_out_redirects_to_sign_in(
|
def test_render_sign_out_redirects_to_sign_in(
|
||||||
client
|
logged_in_client
|
||||||
):
|
):
|
||||||
response = client.get(
|
response = logged_in_client.get(
|
||||||
url_for('main.sign_out'))
|
url_for('main.sign_out'))
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.location == url_for(
|
assert response.location == url_for(
|
||||||
|
|||||||
Reference in New Issue
Block a user