import json from datetime import timedelta from unittest import mock import time from flask import Response from flask.sessions import SecureCookieSessionInterface from itsdangerous import SignatureExpired from jose import ExpiredSignatureError from api.resources import login from api import api def test_not_logged_in_is_401(): app = api.app.test_client() not_authed = app.get('/api/login') assert not_authed.status_code == 401 def test_idtoken_login_gives_session_cookie(monkeypatch): api.app.config['TESTING'] = True # api.app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=20) app = api.app.test_client() mockcognito = mock.Mock( get_user_details=mock.Mock(return_value={'username':'test'}) ) monkeypatch.setattr(login, 'cognito', mockcognito) authed = app.get('/api/login', headers={'Authorization': 'Bearer2 testtesttesttest'}) _, _, is_token = mockcognito.get_user_details.call_args[0] assert is_token == 'testtesttesttest' print(authed.headers.get('Set-Cookie')) assert authed.headers.get('Set-Cookie') is not None, 'A session cookie should be returned' cookie_checker = SecureCookieSessionInterface().get_signing_serializer(api.app) cookie = _get_cookie_to_set(authed) unsigned = cookie_checker.loads(cookie, max_age=5) assert unsigned['user_id'] == 'test' try: time.sleep(1) cookie_checker.loads(cookie, max_age=0.001) except SignatureExpired: pass else: raise AssertionError(f'Should be expired cookie') def _get_cookie_to_set(response : Response): cookie = response.headers.get('Set-Cookie').split(';')[0].split('session=')[-1].strip() return cookie def test_logging_in_sets_cookie(monkeypatch): mockcognito = mock.Mock( get_user_details=mock.Mock(return_value={'username': 'test'}) ) monkeypatch.setattr(login, 'cognito', mockcognito) app = api.app.test_client() app.get('/api/login', headers={'Authorization': 'Bearer2 testtesttesttest'}) # The app get's the user logged_in = app.get('/api/login') assert logged_in.status_code == 200 assert json.loads(logged_in.data)['name'] == 'test' def test_session_cookie_is_refreshed_unless_ignoreForSession_is_passed(monkeypatch): mockcognito = mock.Mock( get_user_details=mock.Mock(return_value={'username': 'test'}) ) monkeypatch.setattr(login, 'cognito', mockcognito) app = api.app.test_client() app.get('/api/login', headers={'Authorization': 'Bearer2 testtesttesttest'}) cookie_checker = SecureCookieSessionInterface().get_signing_serializer(api.app) unsigners = list(cookie_checker.iter_unsigners(salt=None)) logged_in = app.get('/api/login') cookie, timestamp1 = unsigners[0].unsign(_get_cookie_to_set(logged_in), max_age=None, return_timestamp=True) time.sleep(1) logged_in = app.get('/api/login') cookie, timestamp2 = unsigners[0].unsign(_get_cookie_to_set(logged_in), max_age=None, return_timestamp=True) assert timestamp1 < timestamp2, "Cookie should be refreshed" request_no_refresh = app.get('/api/login?_ignoreForSession=1') assert request_no_refresh.headers.get('Set-Cookie') is None, "Should not return cookie." def test_logging_in_with_expired_id_token_gives_421(monkeypatch): mockcognito = mock.Mock( get_user_details=mock.Mock(side_effect=ExpiredSignatureError()) ) monkeypatch.setattr(login, 'cognito', mockcognito) app = api.app.test_client() res = app.get('/api/login', headers={'Authorization': 'Bearer2 thisisexpired'}) assert res.status_code == 421 def test_using_expired_cookie_returns_401(): mockcognito = mock.Mock( get_user_details=mock.Mock(return_value={'username': 'test'}) ) monkeypatch.setattr(login, 'cognito', mockcognito) app = api.app.test_client() app.get('/api/login', headers={'Authorization': 'Bearer2 testtesttesttest'})