diff --git a/cps/admin.py b/cps/admin.py index cd30f7d4..2602dffb 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -34,6 +34,7 @@ from babel.dates import format_datetime from flask import Blueprint, flash, redirect, url_for, abort, request, make_response, send_from_directory, g, Response from flask_login import login_required, current_user, logout_user, confirm_login from flask_babel import gettext as _ +from flask import session as flask_session from sqlalchemy import and_ from sqlalchemy.orm.attributes import flag_modified from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError @@ -98,8 +99,11 @@ def admin_required(f): @admi.before_app_request def before_request(): + # make remember me function work if current_user.is_authenticated: confirm_login() + if not ub.check_user_session(current_user.id, flask_session.get('_id')) and 'opds' not in request.path: + logout_user() g.constants = constants g.user = current_user g.allow_registration = config.config_public_reg diff --git a/cps/ub.py b/cps/ub.py index c334ff59..9b187639 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -27,6 +27,8 @@ from flask import session as flask_session from binascii import hexlify from flask_login import AnonymousUserMixin, current_user +from flask_login import user_logged_in +from contextlib import contextmanager try: from flask_dance.consumer.backend.sqla import OAuthConsumerMixin @@ -61,6 +63,36 @@ Base = declarative_base() searched_ids = {} +def signal_store_user_session(object, user): + store_user_session() + +def store_user_session(): + if flask_session.get('_user_id', ""): + try: + if not check_user_session(flask_session.get('_user_id', ""), flask_session.get('_id', "")): + user_session = User_Sessions(flask_session.get('_user_id', ""), flask_session.get('_id', "")) + session.add(user_session) + session.commit() + except (exc.OperationalError, exc.InvalidRequestError): + session.rollback() + # log.debug(flask_session.get('_id', "")) + +def delete_user_session(user_id, session_key): + try: + # log.debug(session_key) + session.query(User_Sessions).filter(User_Sessions.user_id==user_id, + User_Sessions.session_key==session_key).delete() + session.commit() + except (exc.OperationalError, exc.InvalidRequestError): + session.rollback() + + +def check_user_session(user_id, session_key): + return bool(session.query(User_Sessions).filter(User_Sessions.user_id==user_id, + User_Sessions.session_key==session_key).one_or_none()) + +user_logged_in.connect(signal_store_user_session) + def store_ids(result): ids = list() for element in result: @@ -72,7 +104,7 @@ class UserBase: @property def is_authenticated(self): - return True + return self.is_active def _has_role(self, role_flag): return constants.has_flag(self.role, role_flag) @@ -261,6 +293,17 @@ class Anonymous(AnonymousUserMixin, UserBase): flask_session['view'][page][prop] = value return None +class User_Sessions(Base): + __tablename__ = 'user_session' + + id = Column(Integer, primary_key=True) + user_id = Column(Integer, ForeignKey('user.id')) + session_key = Column(String, default="") + + def __init__(self, user_id, session_key): + self.user_id = user_id + self.session_key = session_key + # Baseclass representing Shelfs in calibre-web in app.db class Shelf(Base): diff --git a/cps/usermanagement.py b/cps/usermanagement.py index 78e80afe..b18cc673 100644 --- a/cps/usermanagement.py +++ b/cps/usermanagement.py @@ -21,7 +21,8 @@ import binascii from sqlalchemy.sql.expression import func from werkzeug.security import check_password_hash -from flask_login import login_required +from flask_login import login_required, login_user + from . import lm, ub, config, constants, services @@ -58,6 +59,7 @@ def load_user_from_request(request): if rp_header_username: user = _fetch_user_by_name(rp_header_username) if user: + login_user(user) return user auth_header = request.headers.get("Authorization") diff --git a/cps/web.py b/cps/web.py index 3176feb5..ab9c4134 100644 --- a/cps/web.py +++ b/cps/web.py @@ -1523,7 +1523,6 @@ def login(): login_result, error = services.ldap.bind_user(form['username'], form['password']) if login_result: login_user(user, remember=bool(form.get('remember_me'))) - #ub.store_user_session() log.debug(u"You are now logged in as: '%s'", user.name) flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.name), category="success") @@ -1531,7 +1530,6 @@ def login(): elif login_result is None and user and check_password_hash(str(user.password), form['password']) \ and user.name != "Guest": login_user(user, remember=bool(form.get('remember_me'))) - #ub.store_user_session() log.info("Local Fallback Login as: '%s'", user.name) flash(_(u"Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known", nickname=user.name), @@ -1561,7 +1559,6 @@ def login(): else: if user and check_password_hash(str(user.password), form['password']) and user.name != "Guest": login_user(user, remember=bool(form.get('remember_me'))) - # ub.store_user_session() log.debug(u"You are now logged in as: '%s'", user.name) flash(_(u"You are now logged in as: '%(nickname)s'", nickname=user.name), category="success") config.config_is_initial = False @@ -1585,7 +1582,7 @@ def login(): @login_required def logout(): if current_user is not None and current_user.is_authenticated: - # ub.delete_user_session(current_user.id, flask_session.get('_id',"")) + ub.delete_user_session(current_user.id, flask_session.get('_id',"")) logout_user() if feature_support['oauth'] and (config.config_login_type == 2 or config.config_login_type == 3): logout_oauth_user() diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index f9a9218a..101769f7 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,20 +37,20 @@
Start Time: 2021-07-29 20:37:20
+Start Time: 2021-07-30 11:44:06
Stop Time: 2021-07-30 00:10:27
+Stop Time: 2021-07-30 15:14:26
Duration: 2h 47 min
+Duration: 2h 45 min
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli.py", line 442, in test_change_password - self.assertTrue(self.login("admin", "@hukl")) -AssertionError: False is not true-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli.py", line 278, in test_cli_SSL_files - self.driver.get("https://127.0.0.1:8083") -selenium.common.exceptions.WebDriverException: Message: Reached error page: about:neterror?e=netTimeout&u=https%3A//127.0.0.1%3A8083/&c=UTF-8&d=Der%20Server%20unter%20127.0.0.1%20braucht%20zu%20lange%2C%20um%20eine%20Antwort%20zu%20senden. - - -During handling of the above exception, another exception occurred: - -Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli.py", line 280, in test_cli_SSL_files - self.assertIsNone("Error", "HTTPS Connection could not established with key/cert file") -AssertionError: 'Error' is not None : HTTPS Connection could not established with key/cert file-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli.py", line 121, in test_cli_different_settings_database - self.fill_db_config({'config_calibre_dir': TEST_DB}) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 243, in fill_db_config - ele = cls.driver.find_element_by_id(key) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in find_element_by_id - return self.find_element(by=By.ID, value=id_) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 976, in find_element - return self.execute(Command.FIND_ELEMENT, { - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute - self.error_handler.check_response(response) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response - raise exception_class(message, screen, stacktrace) -selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [id="config_calibre_dir"]-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli.py", line 393, in test_settingsdb_not_writeable - self.fill_db_config({'config_calibre_dir': TEST_DB}) -selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [id="config_calibre_dir"] - - -During handling of the above exception, another exception occurred: - -Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli.py", line 398, in test_settingsdb_not_writeable - self.assertFalse(True, "Inital config failed with on test nonwriteable database") -AssertionError: True is not false : Inital config failed with on test nonwriteable database-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli_gdrive.py", line 180, in test_cli_gdrive_location - self.assertTrue(self.check_element_on_page((By.ID, "flash_success"))) -AssertionError: False is not true-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_cli_gdrive.py", line 145, in test_gdrive_db_nonwrite - self.start_cw(os.path.join(CALIBRE_WEB_PATH, u'cps.py')) - File "/home/ozzie/Development/calibre-web-test/test/test_cli_gdrive.py", line 137, in start_cw - self.fill_db_config({'config_calibre_dir': TEST_DB}) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 248, in fill_db_config - cls.driver.find_element_by_name("submit").click() - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 80, in click - self._execute(Command.CLICK_ELEMENT) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute - return self._parent.execute(command, params) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute - self.error_handler.check_response(response) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response - raise exception_class(message, screen, stacktrace) -selenium.common.exceptions.WebDriverException: Message: Reached error page: about:neterror?e=netReset&u=http%3A//127.0.0.1%3A8083/admin/dbconfig&c=UTF-8&d=Die%20Verbindung%20zum%20Server%20wurde%20zur%C3%BCckgesetzt%2C%20w%C3%A4hrend%20die%20Seite%20geladen%20wurde.-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_ebook_convert.py", line 94, in test_convert_wrong_excecutable - self.assertEqual(element.text, 'not installed') -AssertionError: 'Execution permissions missing' != 'not installed' -- Execution permissions missing -+ not installed-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_ebook_convert.py", line 416, in test_email_only - self.assertEqual(ret[-1]['result'], 'Finished') -AssertionError: 'Failed' != 'Finished' -- Failed -+ Finished-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen - httplib_response = self._make_request( - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 426, in _make_request - six.raise_from(e, None) - File "-", line 3, in raise_from - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 421, in _make_request - httplib_response = conn.getresponse() - File "/usr/lib/python3.8/http/client.py", line 1344, in getresponse - response.begin() - File "/usr/lib/python3.8/http/client.py", line 307, in begin - version, status, reason = self._read_status() - File "/usr/lib/python3.8/http/client.py", line 276, in _read_status - raise RemoteDisconnected("Remote end closed connection without" -http.client.RemoteDisconnected: Remote end closed connection without response - -During handling of the above exception, another exception occurred: - -Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/adapters.py", line 439, in send - resp = conn.urlopen( - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 726, in urlopen - retries = retries.increment( - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/util/retry.py", line 410, in increment - raise six.reraise(type(error), error, _stacktrace) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/packages/six.py", line 734, in reraise - raise value.with_traceback(tb) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen - httplib_response = self._make_request( - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 426, in _make_request - six.raise_from(e, None) - File " ", line 3, in raise_from - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 421, in _make_request - httplib_response = conn.getresponse() - File "/usr/lib/python3.8/http/client.py", line 1344, in getresponse - response.begin() - File "/usr/lib/python3.8/http/client.py", line 307, in begin - version, status, reason = self._read_status() - File "/usr/lib/python3.8/http/client.py", line 276, in _read_status - raise RemoteDisconnected("Remote end closed connection without" -urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')) - -During handling of the above exception, another exception occurred: - -Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_edit_additional_books.py", line 564, in test_upload_edit_role - r.post('http://127.0.0.1:8083/login', data=payload) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/sessions.py", line 578, in post - return self.request('POST', url, data=data, json=json, **kwargs) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/sessions.py", line 530, in request - resp = self.send(prep, **send_kwargs) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/sessions.py", line 665, in send - history = [resp for resp in gen] - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/sessions.py", line 665, in - history = [resp for resp in gen] - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/sessions.py", line 237, in resolve_redirects - resp = self.send( - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/sessions.py", line 643, in send - r = adapter.send(request, **kwargs) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/requests/adapters.py", line 498, in send - raise ConnectionError(err, request=request) -requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_edit_additional_books.py", line 53, in test_upload_metadata_cbr - self.fill_basic_config({'config_uploading': 1}) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 342, in fill_basic_config - cls._fill_basic_config(elements) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 252, in _fill_basic_config - WebDriverWait(cls.driver, 5).until(EC.presence_of_element_located((By.ID, "config_port"))) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/support/wait.py", line 80, in until - raise TimeoutException(message, screen, stacktrace) -selenium.common.exceptions.TimeoutException: Message:-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_edit_additional_books.py", line 88, in test_upload_metadata_cbt - self.fill_basic_config({'config_uploading': 1}) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 342, in fill_basic_config - cls._fill_basic_config(elements) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 252, in _fill_basic_config - WebDriverWait(cls.driver, 5).until(EC.presence_of_element_located((By.ID, "config_port"))) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/support/wait.py", line 80, in until - raise TimeoutException(message, screen, stacktrace) -selenium.common.exceptions.TimeoutException: Message:-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_edit_additional_books.py", line 234, in test_writeonly_path - self.fill_basic_config({'config_rarfile_location': unrar_path()}) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 342, in fill_basic_config - cls._fill_basic_config(elements) - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 252, in _fill_basic_config - WebDriverWait(cls.driver, 5).until(EC.presence_of_element_located((By.ID, "config_port"))) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/support/wait.py", line 80, in until - raise TimeoutException(message, screen, stacktrace) -selenium.common.exceptions.TimeoutException: Message:-
Traceback (most recent call last): - File "/home/ozzie/Development/calibre-web-test/test/test_edit_additional_books.py", line 39, in tearDownClass - cls.stop_calibre_web() - File "/home/ozzie/Development/calibre-web-test/test/helper_ui.py", line 430, in stop_calibre_web - cls.driver.find_element_by_id('admin_stop').click() - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in find_element_by_id - return self.find_element(by=By.ID, value=id_) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 976, in find_element - return self.execute(Command.FIND_ELEMENT, { - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute - self.error_handler.check_response(response) - File "/home/ozzie/Development/calibre-web-test/venv/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response - raise exception_class(message, screen, stacktrace) -selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [id="admin_stop"]-