From ea7786a193be088c2db2ed02dbce505b23a7199d Mon Sep 17 00:00:00 2001
From: Julian Rother <julian@cccv.de>
Date: Sun, 19 Sep 2021 23:18:51 +0200
Subject: [PATCH] Limit session lifetime to two days

Fixes #3
---
 app.py      | 11 ++++++++++-
 test_app.py | 17 +++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/app.py b/app.py
index 7ac8395..4354df4 100644
--- a/app.py
+++ b/app.py
@@ -1,5 +1,6 @@
 import os
 import secrets
+import datetime
 
 from flask import Flask, session, request, redirect, abort, Response, url_for
 
@@ -20,13 +21,19 @@ def create_app(test_config=None):
 	@app.route('/auth')
 	def auth():
 		try:
+			timestamp = datetime.datetime.fromtimestamp(session['timestamp'])
 			user_id = session['user_id']
 			user_name = session['user_name']
 			user_nickname = session['user_nickname']
 			user_email = session['user_email']
 			user_ldap_dn = session['user_ldap_dn']
 			user_groups = session['user_groups']
-		except KeyError:
+		except (KeyError, OverflowError):
+			session.clear()
+			session['cookies_enabled'] = True
+			abort(401)
+		if datetime.datetime.now() - timestamp > datetime.timedelta(days=2):
+			session.clear()
 			session['cookies_enabled'] = True
 			abort(401)
 		resp = Response('Ok', 200)
@@ -47,6 +54,7 @@ def create_app(test_config=None):
 		# The cookies_enabled check prevents redirect loops:
 		# login (sets state) -> idp_authorize -> callback (no state set) -> login
 		if not session.get('cookies_enabled'):
+			session.clear()
 			session['cookies_enabled'] = True
 			abort(400, description='Enable cookies and reload two times to continue')
 		client = get_oauth()
@@ -76,6 +84,7 @@ def create_app(test_config=None):
 		userinfo = client.get(app.config['OAUTH2_USERINFO_URL']).json()
 
 		session.clear()
+		session['timestamp'] = datetime.datetime.now().timestamp()
 		session['user_id'] = userinfo['id']
 		session['user_name'] = userinfo['name']
 		session['user_nickname'] = userinfo['nickname']
diff --git a/test_app.py b/test_app.py
index cfe4f63..ac4db1c 100644
--- a/test_app.py
+++ b/test_app.py
@@ -5,6 +5,7 @@ except ImportError:
 	from unittest import mock
 import json
 import urllib.parse
+import datetime
 
 from requests import Session, Response
 
@@ -112,6 +113,7 @@ class TestCases(unittest.TestCase):
 		self.assertEqual(r.status_code, 302)
 		self.assertEqual(r.location, 'https://127.0.0.123:7654/app')
 		with self.client.session_transaction() as session:
+			self.assertGreaterEqual(session['timestamp'], (datetime.datetime.now() - datetime.timedelta(seconds=60)).timestamp())
 			self.assertEqual(session['user_id'], 1234)
 			self.assertEqual(session['user_name'], 'Test User')
 			self.assertEqual(session['user_nickname'], 'testuser')
@@ -133,6 +135,7 @@ class TestCases(unittest.TestCase):
 
 	def test_auth_session(self):
 		with self.client.session_transaction() as session:
+			session['timestamp'] = datetime.datetime.now().timestamp()
 			session['user_id'] = 1234
 			session['user_name'] = 'Test User'
 			session['user_nickname'] = 'testuser'
@@ -148,8 +151,21 @@ class TestCases(unittest.TestCase):
 		self.assertEqual(r.headers['OAUTH-USER-LDAP-DN'], 'uid=testuser,ou=users,dc=example,dc=com')
 		self.assertIn(r.headers['OAUTH-USER-GROUPS'], ['uffd_access,users', 'users,uffd_access'])
 
+	def test_auth_session_timeout(self):
+		with self.client.session_transaction() as session:
+			session['timestamp'] = (datetime.datetime.now() - datetime.timedelta(days=3)).timestamp()
+			session['user_id'] = 1234
+			session['user_name'] = 'Test User'
+			session['user_nickname'] = 'testuser'
+			session['user_email'] = 'test@example.com'
+			session['user_ldap_dn'] = 'uid=testuser,ou=users,dc=example,dc=com'
+			session['user_groups'] = ['uffd_access', 'users']
+		r = self.client.get(path='/auth', headers=headers)
+		self.assertEqual(r.status_code, 401)
+
 	def test_logout(self):
 		with self.client.session_transaction() as session:
+			session['timestamp'] = datetime.datetime.now().timestamp()
 			session['user_id'] = 1234
 			session['user_name'] = 'Test User'
 			session['user_nickname'] = 'testuser'
@@ -169,6 +185,7 @@ class TestCases(unittest.TestCase):
 
 	def test_logout_redirect(self):
 		with self.client.session_transaction() as session:
+			session['timestamp'] = datetime.datetime.now().timestamp()
 			session['user_id'] = 1234
 			session['user_name'] = 'Test User'
 			session['user_nickname'] = 'testuser'
-- 
GitLab