Skip to content

Commit

Permalink
better logged in session protection
Browse files Browse the repository at this point in the history
  • Loading branch information
OzzieIsaacs committed Jul 30, 2021
1 parent e245a14 commit a63baa1
Show file tree
Hide file tree
Showing 5 changed files with 492 additions and 2,123 deletions.
4 changes: 4 additions & 0 deletions cps/admin.py
Expand Up @@ -34,6 +34,7 @@
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
Expand Down Expand Up @@ -98,8 +99,11 @@ def inner(*args, **kwargs):

@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
Expand Down
45 changes: 44 additions & 1 deletion cps/ub.py
Expand Up @@ -27,6 +27,8 @@
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
Expand Down Expand Up @@ -61,6 +63,36 @@
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:
Expand All @@ -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)
Expand Down Expand Up @@ -261,6 +293,17 @@ def set_view_property(self, page, prop, value):
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):
Expand Down
4 changes: 3 additions & 1 deletion cps/usermanagement.py
Expand Up @@ -21,7 +21,8 @@

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

Expand Down Expand Up @@ -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")
Expand Down
5 changes: 1 addition & 4 deletions cps/web.py
Expand Up @@ -1523,15 +1523,13 @@ 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")
return redirect_back(url_for("web.index"))
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),
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down

0 comments on commit a63baa1

Please sign in to comment.