Validate the session without using the pool on bus requests
This commit is contained in:
@@ -226,7 +226,7 @@ else:
|
||||
|
||||
|
||||
@app.route('/<string:database_name>/bus', methods=['POST'])
|
||||
@app.auth_required
|
||||
@app.session_valid
|
||||
def subscribe(request, database_name):
|
||||
if not _allow_subscribe:
|
||||
raise exceptions.NotImplemented
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import datetime as dt
|
||||
import ipaddress
|
||||
import logging
|
||||
import random
|
||||
import time
|
||||
from secrets import compare_digest
|
||||
|
||||
try:
|
||||
from http import HTTPStatus
|
||||
except ImportError:
|
||||
from http import client as HTTPStatus
|
||||
|
||||
from sql import Table
|
||||
from sql.conditionals import Coalesce
|
||||
from werkzeug.exceptions import abort
|
||||
|
||||
from trytond import backend
|
||||
@@ -168,6 +172,33 @@ def check_timeout(dbname, user, session, context=None):
|
||||
return valid
|
||||
|
||||
|
||||
def check_session(dbname, user, session, remote_addr=None):
|
||||
"Check the session without using the pool"
|
||||
database = backend.Database(dbname)
|
||||
now = dt.datetime.now()
|
||||
timeout = dt.timedelta(config.getint('session', 'max_age'))
|
||||
conn = database.get_connection(readonly=True)
|
||||
if remote_addr:
|
||||
ip_addr = str(ipaddress.ip_address(remote_addr))
|
||||
else:
|
||||
ip_addr = None
|
||||
try:
|
||||
ir_session = Table('ir_session')
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(*ir_session.select(
|
||||
Coalesce(ir_session.write_date, ir_session.create_date),
|
||||
ir_session.key,
|
||||
where=((ir_session.create_uid == user)
|
||||
& (ir_session.ip_address == ip_addr))))
|
||||
for session_date, session_key in cursor:
|
||||
if abs(session_date - now) < timeout:
|
||||
if compare_digest(session_key, session):
|
||||
return True
|
||||
return False
|
||||
finally:
|
||||
database.put_connection(conn)
|
||||
|
||||
|
||||
def reset(dbname, session, context):
|
||||
try:
|
||||
with Transaction().start(dbname, 0, context=context, autocommit=True):
|
||||
|
||||
+28
-6
@@ -27,7 +27,7 @@ try:
|
||||
except ImportError:
|
||||
from werkzeug.wsgi import SharedDataMiddleware
|
||||
|
||||
from trytond import backend
|
||||
from trytond import backend, security
|
||||
from trytond.config import config
|
||||
from trytond.protocols.jsonrpc import JSONProtocol
|
||||
from trytond.protocols.wrappers import (
|
||||
@@ -41,6 +41,14 @@ __all__ = ['TrytondWSGI', 'app']
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _do_basic_auth(request):
|
||||
headers = {}
|
||||
if request.headers.get('X-Requested-With') != 'XMLHttpRequest':
|
||||
headers['WWW-Authenticate'] = 'Basic realm="Tryton"'
|
||||
response = Response(None, http.client.UNAUTHORIZED, headers)
|
||||
abort(http.client.UNAUTHORIZED, response=response)
|
||||
|
||||
|
||||
class Base64Converter(BaseConverter):
|
||||
|
||||
def to_python(self, value):
|
||||
@@ -81,11 +89,25 @@ class TrytondWSGI(object):
|
||||
if request.user_id:
|
||||
return func(request, *args, **kwargs)
|
||||
else:
|
||||
headers = {}
|
||||
if request.headers.get('X-Requested-With') != 'XMLHttpRequest':
|
||||
headers['WWW-Authenticate'] = 'Basic realm="Tryton"'
|
||||
response = Response(None, http.client.UNAUTHORIZED, headers)
|
||||
abort(http.client.UNAUTHORIZED, response=response)
|
||||
_do_basic_auth(request)
|
||||
return wrapper
|
||||
|
||||
def session_valid(self, func):
|
||||
@wraps(func)
|
||||
def wrapper(request, *args, **kwargs):
|
||||
if (not request.authorization
|
||||
or request.authorization.type != 'session'):
|
||||
_do_basic_auth(request)
|
||||
userid = request.authorization.get('userid')
|
||||
session = request.authorization.get('session')
|
||||
dbname = request.view_args.get('database_name')
|
||||
|
||||
if not security.check_session(
|
||||
dbname, userid, session, request.remote_addr):
|
||||
_do_basic_auth(request)
|
||||
|
||||
return func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
def dispatch_request(self, request):
|
||||
|
||||
Reference in New Issue
Block a user