Skip to content

Commit 58b6db8

Browse files
authored
Merge pull request #2828 from stveit/flush-session-on-logout
Flush session on logout
2 parents 16d3c1b + 45cea1f commit 58b6db8

File tree

9 files changed

+174
-97
lines changed

9 files changed

+174
-97
lines changed

python/nav/web/auth/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from nav.models.profiles import Account, AccountGroup
2929
from nav.web.auth import ldap, remote_user
3030
from nav.web.auth.sudo import desudo
31-
from nav.web.auth.utils import ACCOUNT_ID_VAR
31+
from nav.web.auth.utils import clear_session
3232

3333

3434
_logger = logging.getLogger(__name__)
@@ -151,10 +151,7 @@ def logout(request, sudo=False):
151151
return reverse('webfront-index')
152152
else:
153153
account = request.account
154-
del request.session[ACCOUNT_ID_VAR]
155-
del request.account
156-
request.session.set_expiry(datetime.now())
157-
request.session.save()
154+
clear_session(request)
158155
_logger.debug('logout: logout %s', account.login)
159156
LogEntry.add_log_entry(account, 'log-out', '{actor} logged out', before=account)
160157
_logger.debug('logout: redirect to "/" after logout')

python/nav/web/auth/sudo.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from nav.auditlog.models import LogEntry
2323
from nav.django.utils import is_admin, get_account
2424
from nav.models.profiles import Account
25-
from nav.web.auth.utils import set_account, ACCOUNT_ID_VAR
25+
from nav.web.auth.utils import set_account, clear_session
2626

2727

2828
_logger = logging.getLogger(__name__)
@@ -68,8 +68,7 @@ def desudo(request):
6868
original_user_id = request.session[SUDOER_ID_VAR]
6969
original_user = Account.objects.get(id=original_user_id)
7070

71-
del request.session[ACCOUNT_ID_VAR]
72-
del request.session[SUDOER_ID_VAR]
71+
clear_session(request)
7372
set_account(request, original_user)
7473
_logger.info(
7574
'DeSudo: "%s" no longer acting as "%s"', original_user, request.account

python/nav/web/auth/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ def set_account(request, account, cycle_session_id=True):
4343
request.session.save()
4444

4545

46+
def clear_session(request):
47+
"""Clears the session and logs out the current account"""
48+
if hasattr(request, "account"):
49+
del request.account
50+
request.session.flush()
51+
request.session.save()
52+
53+
4654
def ensure_account(request):
4755
"""Guarantee that valid request.account is set"""
4856
session = request.session
@@ -51,6 +59,9 @@ def ensure_account(request):
5159
account = Account.objects.get(id=account_id)
5260

5361
if account.locked:
62+
# logout of locked account
63+
clear_session(request)
64+
5465
# Switch back to fallback, the anonymous user
5566
# Assumes nobody has locked it..
5667
account = Account.objects.get(id=Account.DEFAULT_ACCOUNT)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from nav.web.auth import logout
2+
from nav.web.auth.utils import ACCOUNT_ID_VAR, set_account
3+
from nav.web.auth.sudo import sudo
4+
5+
6+
class TestLogout:
7+
def test_non_sudo_logout_should_remove_session_data(
8+
self, db, session_request, admin_account
9+
):
10+
# login with admin acount
11+
set_account(session_request, admin_account)
12+
logout(session_request)
13+
assert not hasattr(session_request, 'account')
14+
assert ACCOUNT_ID_VAR not in session_request.session
15+
16+
def test_non_sudo_logout_should_return_path_to_index(
17+
self, db, session_request, admin_account
18+
):
19+
# login with admin acount
20+
set_account(session_request, admin_account)
21+
result = logout(session_request)
22+
assert result == '/'
23+
24+
def test_sudo_logout_should_set_session_to_original_user(
25+
self, db, session_request, admin_account, account
26+
):
27+
# login with admin acount
28+
set_account(session_request, admin_account)
29+
sudo(session_request, account)
30+
assert session_request.account is account
31+
result = logout(session_request, sudo=True)
32+
assert result == '/'
33+
assert session_request.account == admin_account
34+
35+
def test_non_sudo_logout_should_change_session_id(
36+
self, db, session_request, admin_account
37+
):
38+
# login with admin acount
39+
set_account(session_request, admin_account)
40+
pre_session_id = session_request.session.session_key
41+
logout(session_request)
42+
post_session_id = session_request.session.session_key
43+
assert post_session_id != pre_session_id
44+
45+
def test_sudo_logout_should_change_session_id(
46+
self, db, session_request, admin_account, account
47+
):
48+
# login with admin acount
49+
set_account(session_request, admin_account)
50+
sudo(session_request, account)
51+
pre_session_id = session_request.session.session_key
52+
logout(session_request, sudo=True)
53+
post_session_id = session_request.session.session_key
54+
assert post_session_id != pre_session_id

tests/integration/web/auth/conftest.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,31 @@ def session_request(db):
1515
middleware.process_request(session_request)
1616
session_request.session.save()
1717
return session_request
18+
19+
20+
@pytest.fixture()
21+
def account(db):
22+
from nav.models.profiles import Account
23+
24+
account = Account(login="other_user")
25+
account.set_password("password")
26+
account.save()
27+
yield account
28+
account.delete()
29+
30+
31+
@pytest.fixture()
32+
def locked_account(db):
33+
from nav.models.profiles import Account
34+
35+
account = Account(login="locked_user")
36+
account.save()
37+
yield account
38+
account.delete()
39+
40+
41+
@pytest.fixture()
42+
def default_account(db):
43+
from nav.models.profiles import Account
44+
45+
return Account.objects.get(id=Account.DEFAULT_ACCOUNT)
Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,15 @@
1-
import pytest
21
from mock import patch
32

43
from nav.web.auth.middleware import AuthenticationMiddleware
5-
from nav.models.profiles import Account
64

75

86
def test_when_remote_user_logs_in_it_should_change_the_session_id(
9-
db, session_request, remote_account
7+
db, session_request, account
108
):
119
pre_login_session_id = session_request.session.session_key
12-
with patch(
13-
'nav.web.auth.remote_user.get_username', return_value=remote_account.login
14-
):
10+
with patch('nav.web.auth.remote_user.get_username', return_value=account.login):
1511
middleware = AuthenticationMiddleware(lambda request: None)
1612
middleware.process_request(session_request)
17-
assert session_request.account == remote_account
13+
assert session_request.account == account
1814
post_login_session_id = session_request.session.session_key
1915
assert pre_login_session_id != post_login_session_id
20-
21-
22-
@pytest.fixture()
23-
def remote_account(db):
24-
account = Account(login="remote")
25-
account.set_password("supersecret")
26-
account.save()
27-
yield account
28-
account.delete()
Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,26 @@
1-
import pytest
2-
3-
from django.test import RequestFactory
4-
51
from nav.web.auth.utils import set_account
62
from nav.web.auth.sudo import sudo, desudo
7-
from nav.models.profiles import Account
83

94

10-
def test_sudo_should_change_session_id(
11-
db, session_request, admin_account, other_account
12-
):
5+
def test_sudo_should_change_session_id(db, session_request, admin_account, account):
136
# login with admin acount
147
set_account(session_request, admin_account)
158

169
pre_sudo_session_id = session_request.session.session_key
17-
sudo(session_request, other_account)
10+
sudo(session_request, account)
1811
post_sudo_session_id = session_request.session.session_key
1912

2013
assert pre_sudo_session_id != post_sudo_session_id
2114

2215

23-
def test_desudo_should_change_session_id(
24-
db, session_request, admin_account, other_account
25-
):
16+
def test_desudo_should_change_session_id(db, session_request, admin_account, account):
2617
# login with admin acount
2718
set_account(session_request, admin_account)
2819

29-
sudo(session_request, other_account)
20+
sudo(session_request, account)
3021

3122
pre_desudo_session_id = session_request.session.session_key
3223
desudo(session_request)
3324
post_desudo_session_id = session_request.session.session_key
3425

3526
assert pre_desudo_session_id != post_desudo_session_id
36-
37-
38-
@pytest.fixture()
39-
def other_account(db):
40-
account = Account(login="other_user")
41-
account.save()
42-
yield account
43-
account.delete()
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from nav.web.auth.utils import (
2+
set_account,
3+
clear_session,
4+
ACCOUNT_ID_VAR,
5+
ensure_account,
6+
)
7+
8+
9+
class TestClearSession:
10+
def test_should_create_new_session_id(self, db, session_request):
11+
pre_session_id = session_request.session.session_key
12+
clear_session(session_request)
13+
post_session_id = session_request.session.session_key
14+
assert pre_session_id != post_session_id
15+
16+
def test_should_remove_account_from_request(
17+
self, db, session_request, admin_account
18+
):
19+
# login with admin acount
20+
set_account(session_request, admin_account)
21+
assert session_request.account
22+
clear_session(session_request)
23+
assert not hasattr(session_request, "account")
24+
25+
def test_should_clear_session_dict(self, db, session_request, admin_account):
26+
set_account(session_request, admin_account)
27+
# Make sure there is something to be deleted
28+
assert session_request.session.keys()
29+
clear_session(session_request)
30+
assert not session_request.session.keys()
31+
32+
33+
class TestEnsureAccount:
34+
def test_account_should_be_set_if_request_does_not_already_have_an_account(
35+
self, db, session_request
36+
):
37+
assert not hasattr(session_request, "account")
38+
ensure_account(session_request)
39+
assert (
40+
ACCOUNT_ID_VAR in session_request.session
41+
), 'Account id is not in the session'
42+
assert hasattr(session_request, 'account'), 'Account not set'
43+
assert (
44+
session_request.account.id == session_request.session[ACCOUNT_ID_VAR]
45+
), 'Correct user not set'
46+
47+
def test_account_should_be_switched_to_default_if_locked(
48+
self, db, session_request, locked_account, default_account
49+
):
50+
set_account(session_request, locked_account)
51+
ensure_account(session_request)
52+
assert session_request.session[ACCOUNT_ID_VAR] == default_account.id
53+
assert session_request.account == default_account, 'Correct user not set'
54+
55+
def test_account_should_be_unchanged_if_ok(self, db, session_request, account):
56+
set_account(session_request, account)
57+
ensure_account(session_request)
58+
assert session_request.account == account
59+
assert session_request.session[ACCOUNT_ID_VAR] == account.id
60+
61+
def test_session_id_should_be_changed_if_going_from_locked_to_default_account(
62+
self, db, session_request, locked_account, default_account
63+
):
64+
set_account(session_request, locked_account)
65+
pre_session_id = session_request.session.session_key
66+
ensure_account(session_request)
67+
assert session_request.account == default_account
68+
post_session_id = session_request.session.session_key
69+
assert post_session_id != pre_session_id

tests/unittests/general/web_middleware_test.py

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from django.test import RequestFactory
55

6-
from nav.web.auth.utils import ACCOUNT_ID_VAR, set_account, ensure_account
6+
from nav.web.auth.utils import ACCOUNT_ID_VAR, set_account
77
from nav.web.auth.sudo import SUDOER_ID_VAR
88
from nav.web.auth.middleware import AuthenticationMiddleware
99
from nav.web.auth.middleware import AuthorizationMiddleware
@@ -33,45 +33,6 @@ def test_set_account(fake_session):
3333
assert request.session[ACCOUNT_ID_VAR] == DEFAULT_ACCOUNT.id
3434

3535

36-
class TestEnsureAccount(object):
37-
def test_account_is_set_if_missing(self, fake_session):
38-
r = RequestFactory()
39-
request = r.get('/')
40-
request.session = fake_session
41-
with patch("nav.web.auth.Account.objects.get", return_value=DEFAULT_ACCOUNT):
42-
ensure_account(request)
43-
assert (
44-
auth.ACCOUNT_ID_VAR in request.session
45-
), 'Account id is not in the session'
46-
assert hasattr(request, 'account'), 'Account not set'
47-
assert (
48-
request.account.id == request.session[auth.ACCOUNT_ID_VAR]
49-
), 'Correct user not set'
50-
51-
def test_account_is_switched_to_default_if_locked(self, fake_session):
52-
r = RequestFactory()
53-
request = r.get('/')
54-
request.session = fake_session
55-
request.session[auth.ACCOUNT_ID_VAR] = LOCKED_ACCOUNT.id
56-
with patch(
57-
"nav.web.auth.Account.objects.get",
58-
side_effect=[LOCKED_ACCOUNT, DEFAULT_ACCOUNT],
59-
):
60-
ensure_account(request)
61-
assert request.session[auth.ACCOUNT_ID_VAR] == DEFAULT_ACCOUNT.id
62-
assert request.account == DEFAULT_ACCOUNT, 'Correct user not set'
63-
64-
def test_account_is_left_alone_if_ok(self, fake_session):
65-
r = RequestFactory()
66-
request = r.get('/')
67-
request.session = fake_session
68-
request.session[auth.ACCOUNT_ID_VAR] = return_value = PLAIN_ACCOUNT.id
69-
with patch("nav.web.auth.Account.objects.get", return_value=PLAIN_ACCOUNT):
70-
ensure_account(request)
71-
assert request.account == PLAIN_ACCOUNT
72-
assert request.session[auth.ACCOUNT_ID_VAR] == PLAIN_ACCOUNT.id
73-
74-
7536
class TestAuthenticationMiddleware(object):
7637
def test_process_request_logged_in(self, fake_session):
7738
r = RequestFactory()
@@ -215,18 +176,6 @@ def test_logout_before_login(self):
215176
result = logout(fake_request)
216177
assert result == None
217178

218-
def test_non_sudo_logout(self, fake_session):
219-
r = RequestFactory()
220-
fake_request = r.get('/anyurl')
221-
fake_session[ACCOUNT_ID_VAR] = PLAIN_ACCOUNT.id
222-
fake_request.session = fake_session
223-
fake_request.account = PLAIN_ACCOUNT
224-
with patch('nav.web.auth.LogEntry.add_log_entry'):
225-
result = logout(fake_request)
226-
assert result == '/'
227-
assert not hasattr(fake_request, 'account')
228-
assert ACCOUNT_ID_VAR not in fake_request.session
229-
230179
def test_sudo_logout(self, fake_session):
231180
r = RequestFactory()
232181
fake_request = r.post('/anyurl', data={'submit_desudo': True})

0 commit comments

Comments
 (0)