proxy login is now no longer saving cookies,

Cookies are saved in database for better Invalidation
Cookies expiry date is saved in database for further deletion (missing)
Database conversion is missing
This commit is contained in:
Ozzie Isaacs
2024-07-14 16:24:07 +02:00
parent 2d470e0ce1
commit ebe7cd7ba4
32 changed files with 1524 additions and 233 deletions

View File

@@ -19,16 +19,121 @@
from functools import wraps
from sqlalchemy.sql.expression import func
from flask_login import login_required, login_user
from .cw_login import login_required
from flask import request, g
from flask_httpauth import HTTPBasicAuth
from werkzeug.datastructures import Authorization
from werkzeug.security import check_password_hash
from . import lm, ub, config, logger, limiter, constants, services
from . import lm, ub, config, logger, limiter
log = logger.create()
'''class HTTPProxyAuth(HTTPAuth):
def __init__(self, scheme='Proxy', realm=None, header=None):
super(HTTPProxyAuth, self).__init__(scheme, realm, header)
self.user = None
self.verify_user_callback = None
def set_user(self, username):
self.user = username if username else None
def verify_login(self, f):
self.verify_user_callback = f
return f
def login_required(self, f=None, role=None, optional=None):
if f is not None and \
(role is not None or optional is not None): # pragma: no cover
raise ValueError(
'role and optional are the only supported arguments')
def login_required_internal(f):
@wraps(f)
def decorated(*args, **kwargs):
if self.user:
g.flask_httpauth_user = self.user
return self.ensure_sync(f)(*args, **kwargs)
return decorated
if f:
return login_required_internal(f)
return login_required_internal
def authenticate(self, _auth, stored_password=None):
req = getattr(_auth, 'req', '')
if self.verify_user_callback:
return self.ensure_sync(self.verify_user_callback)(req)'''
auth = HTTPBasicAuth()
# proxy_auth = HTTPProxyAuth()
@auth.verify_password
def verify_password(username, password):
user = ub.session.query(ub.User).filter(func.lower(ub.User.name) == username.lower()).first()
if user:
if user.name.lower() == "guest":
if config.config_anonbrowse == 1:
return user
if config.config_login_type == constants.LOGIN_LDAP and services.ldap:
login_result, error = services.ldap.bind_user(user.name, password)
if login_result:
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
return user
if error is not None:
log.error(error)
elif check_password_hash(str(user.password), password):
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
return user
ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
log.warning('OPDS Login failed for user "%s" IP-address: %s', username, ip_address)
return None
def requires_basic_auth_if_no_ano(f):
@wraps(f)
def decorated(*args, **kwargs):
authorisation = auth.get_auth()
status = None
user = None
if config.config_allow_reverse_proxy_header_login and not authorisation:
user = load_user_from_reverse_proxy_header(request)
if config.config_anonbrowse == 1 and not authorisation:
authorisation = Authorization(
b"Basic", {'username': "Guest", 'password': ""})
if not user:
user = auth.authenticate(authorisation, "")
if user in (False, None):
status = 401
if status:
try:
return auth.auth_error_callback(status)
except TypeError:
return auth.auth_error_callback()
g.flask_httpauth_user = user if user is not True \
else auth.username if auth else None
return auth.ensure_sync(f)(*args, **kwargs)
return decorated
def login_required_if_no_ano(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if config.config_allow_reverse_proxy_header_login:
user = load_user_from_reverse_proxy_header(request)
if user:
g.flask_httpauth_user = user
return func(*args, **kwargs)
# proxy_auth.set_user(user)
# return proxy_auth.login_required(func)(*args, **kwargs)
g.flask_httpauth_user = None
if config.config_anonbrowse == 1:
return func(*args, **kwargs)
return login_required(func)(*args, **kwargs)
@@ -36,47 +141,39 @@ def login_required_if_no_ano(func):
return decorated_view
'''def _load_user_from_auth_header(username, password):
limiter.check()
user = _fetch_user_by_name(username)
if bool(user and check_password_hash(str(user.password), password)) and user.name != "Guest":
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
login_user(user)
return user
else:
ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
log.warning('OPDS Login failed for user "%s" IP-address: %s', username, ip_address)
return None
def user_login_required(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if config.config_allow_reverse_proxy_header_login:
user = load_user_from_reverse_proxy_header(request)
if user:
g.flask_httpauth_user = user
return func(*args, **kwargs)
g.flask_httpauth_user = None
return login_required(func)(*args, **kwargs)
return decorated_view
def _authenticate():
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})'''
def _fetch_user_by_name(username):
return ub.session.query(ub.User).filter(func.lower(ub.User.name) == username.lower()).first()
def load_user_from_reverse_proxy_header(req):
rp_header_name = config.config_reverse_proxy_login_header_name
if rp_header_name:
rp_header_username = req.headers.get(rp_header_name)
if rp_header_username:
user = ub.session.query(ub.User).filter(func.lower(ub.User.name) == rp_header_username.lower()).first()
if user:
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
return user
return None
@lm.user_loader
def load_user(user_id):
def load_user(user_id, random, session_key):
user = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first()
return user
@lm.request_loader
def load_user_from_reverse_proxy_header(req):
if config.config_allow_reverse_proxy_header_login:
rp_header_name = config.config_reverse_proxy_login_header_name
if rp_header_name:
rp_header_username = req.headers.get(rp_header_name)
if rp_header_username:
user = _fetch_user_by_name(rp_header_username)
if user:
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
login_user(user)
return user
return None
entry = ub.session.query(ub.User_Sessions).filter(ub.User_Sessions.random == random,
ub.User_Sessions.session_key == session_key).first()
if entry and entry.id == user.id:
return user
else:
return None