From 21f6df36b0d57fa515bc72612ceb04c019c3c13f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Tue, 1 Jun 2021 13:17:53 +0200 Subject: [PATCH] Refactor for all middlewares (now are all on same place..) --- server/src/server/settings.py.sample | 6 +- server/src/uds/auths/Radius/__init__.py | 2 - .../src/uds/core/util/middleware/__init__.py | 69 +------ .../src/uds/core/util/middleware/redirect.py | 78 ++++++++ .../src/uds/core/util/middleware/request.py | 160 +++++++++++++++ server/src/uds/core/util/middleware/xua.py | 54 +++++ server/src/uds/core/util/request.py | 186 ++++-------------- 7 files changed, 331 insertions(+), 224 deletions(-) create mode 100644 server/src/uds/core/util/middleware/redirect.py create mode 100644 server/src/uds/core/util/middleware/request.py create mode 100644 server/src/uds/core/util/middleware/xua.py diff --git a/server/src/server/settings.py.sample b/server/src/server/settings.py.sample index 7cb89540..40d2e381 100644 --- a/server/src/server/settings.py.sample +++ b/server/src/server/settings.py.sample @@ -175,9 +175,9 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', - 'uds.core.util.request.GlobalRequestMiddleware', - 'uds.core.util.middleware.XUACompatibleMiddleware', - 'uds.core.util.middleware.RedirectMiddleware', + 'uds.core.util.middleware.request.GlobalRequestMiddleware', + 'uds.core.util.middleware.xua.XUACompatibleMiddleware', + 'uds.core.util.middleware.redirect.RedirectMiddleware', ] SESSION_EXPIRE_AT_BROWSER_CLOSE = True diff --git a/server/src/uds/auths/Radius/__init__.py b/server/src/uds/auths/Radius/__init__.py index 12b8672f..1e26166a 100644 --- a/server/src/uds/auths/Radius/__init__.py +++ b/server/src/uds/auths/Radius/__init__.py @@ -35,5 +35,3 @@ take care of registering it as provider .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com """ from .authenticator import RadiusAuth - -__updated__ = '2014-02-19' diff --git a/server/src/uds/core/util/middleware/__init__.py b/server/src/uds/core/util/middleware/__init__.py index 63927b0b..cdb78c7f 100644 --- a/server/src/uds/core/util/middleware/__init__.py +++ b/server/src/uds/core/util/middleware/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2013-2020 Virtual Cable S.L.U. +# Copyright (c) 2013-2021 Virtual Cable S.L.U. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, @@ -25,70 +25,3 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import logging - -from django.urls import reverse -from django.http import HttpResponseRedirect -from uds.core.util.config import GlobalConfig - -logger = logging.getLogger(__name__) - - -class XUACompatibleMiddleware: - """ - Add a X-UA-Compatible header to the response - This header tells to Internet Explorer to render page with latest - possible version or to use chrome frame if it is installed. - """ - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - response = self.get_response(request) - if response.get('content-type', '').startswith('text/html'): - response['X-UA-Compatible'] = 'IE=edge' - return response - - -class RedirectMiddleware: - """ - This class is responsible of redirection, if checked, requests to HTTPS. - - Some paths will not be redirected, to avoid problems, but they are advised to use SSL (this is for backwards compat) - """ - NO_REDIRECT = [ - 'rest', - 'pam', - 'guacamole', - # For new paths - # 'uds/rest', # REST must be HTTPS if redirect is enabled - 'uds/pam', - 'uds/guacamole', - 'uds/rest/client/test' - ] - - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - full_path = request.get_full_path() - redirect = True - for nr in RedirectMiddleware.NO_REDIRECT: - if full_path.startswith('/' + nr): - redirect = False - break - - if redirect and request.is_secure() is False and GlobalConfig.REDIRECT_TO_HTTPS.getBool(): - if request.method == 'POST': - # url = request.build_absolute_uri(GlobalConfig.LOGIN_URL.get()) - url = reverse('page.login') - else: - url = request.build_absolute_uri(full_path) - url = url.replace('http://', 'https://') - - return HttpResponseRedirect(url) - return self.get_response(request) - - @staticmethod - def registerException(path: str) -> None: - RedirectMiddleware.NO_REDIRECT.append(path) diff --git a/server/src/uds/core/util/middleware/redirect.py b/server/src/uds/core/util/middleware/redirect.py new file mode 100644 index 00000000..17eb0678 --- /dev/null +++ b/server/src/uds/core/util/middleware/redirect.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013-2021 Virtual Cable S.L.U. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import logging + +from django.urls import reverse +from django.http import HttpResponseRedirect +from uds.core.util.config import GlobalConfig + +logger = logging.getLogger(__name__) + + +class RedirectMiddleware: + """ + This class is responsible of redirection, if checked, requests to HTTPS. + + Some paths will not be redirected, to avoid problems, but they are advised to use SSL (this is for backwards compat) + """ + NO_REDIRECT = [ + 'rest', + 'pam', + 'guacamole', + # For new paths + # 'uds/rest', # REST must be HTTPS if redirect is enabled + 'uds/pam', + 'uds/guacamole', + 'uds/rest/client/test' + ] + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + full_path = request.get_full_path() + redirect = True + for nr in RedirectMiddleware.NO_REDIRECT: + if full_path.startswith('/' + nr): + redirect = False + break + + if redirect and request.is_secure() is False and GlobalConfig.REDIRECT_TO_HTTPS.getBool(): + if request.method == 'POST': + # url = request.build_absolute_uri(GlobalConfig.LOGIN_URL.get()) + url = reverse('page.login') + else: + url = request.build_absolute_uri(full_path) + url = url.replace('http://', 'https://') + + return HttpResponseRedirect(url) + return self.get_response(request) + + @staticmethod + def registerException(path: str) -> None: + RedirectMiddleware.NO_REDIRECT.append(path) diff --git a/server/src/uds/core/util/middleware/request.py b/server/src/uds/core/util/middleware/request.py new file mode 100644 index 00000000..cbb6c2b4 --- /dev/null +++ b/server/src/uds/core/util/middleware/request.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2012-2021 Virtual Cable S.L.U. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com +""" +import threading +import datetime +import weakref +import logging +import typing + +from django.http import HttpRequest, HttpResponse +from django.utils import timezone + +from uds.core.util import os_detector as OsDetector +from uds.core.util.config import GlobalConfig +from uds.core.auths.auth import EXPIRY_KEY, ROOT_ID, USER_KEY, getRootUser, webLogout +from uds.core.util.request import setRequest, delCurrentRequest, cleanOldRequests, ExtendedHttpRequest +from uds.models import User + +logger = logging.getLogger(__name__) + +# How often to check the requests cache for stuck objects +CHECK_SECONDS = 3600 * 24 # Once a day is more than enough + + +class GlobalRequestMiddleware: + lastCheck: typing.ClassVar[datetime.datetime] = datetime.datetime.now() + + def __init__(self, get_response: typing.Callable[[HttpRequest], HttpResponse]): + self._get_response: typing.Callable[[HttpRequest], HttpResponse] = get_response + + def _process_request(self, request: ExtendedHttpRequest) -> None: + # Store request on cache + setRequest(request=request) + + # Add IP to request + GlobalRequestMiddleware.fillIps(request) + # Ensures request contains os + request.os = OsDetector.getOsFromUA( + request.META.get('HTTP_USER_AGENT', 'Unknown') + ) + # Ensures that requests contains the valid user + GlobalRequestMiddleware.getUser(request) + + def _process_response(self, request: ExtendedHttpRequest, response: HttpResponse): + # Remove IP from global cache (processing responses after this will make global request unavailable, + # but can be got from request again) + delCurrentRequest() + # Clean old stored if needed + GlobalRequestMiddleware.cleanStuckRequests() + + return response + + def __call__(self, request: ExtendedHttpRequest): + self._process_request(request) + + # Now, check if session is timed out... + if request.user: + # return HttpResponse(content='Session Expired', status=403, content_type='text/plain') + now = timezone.now() + expiry = request.session.get(EXPIRY_KEY, now) + if expiry < now: + webLogout( + request=request + ) # Ignore the response, just processes usere session logout + return HttpResponse(content='Session Expired', status=403) + # Update session timeout..self. + request.session[EXPIRY_KEY] = now + datetime.timedelta( + seconds=GlobalConfig.SESSION_DURATION_ADMIN.getInt() + if request.user.isStaff() + else GlobalConfig.SESSION_DURATION_USER.getInt() + ) + + response = self._get_response(request) + + return self._process_response(request, response) + + @staticmethod + def cleanStuckRequests() -> None: + # In case of some exception, keep clean very old request from time to time... + if ( + GlobalRequestMiddleware.lastCheck + > datetime.datetime.now() - datetime.timedelta(seconds=CHECK_SECONDS) + ): + return + cleanOldRequests() + + @staticmethod + def fillIps(request: ExtendedHttpRequest): + """ + Obtains the IP of a Django Request, even behind a proxy + + Returns the obtained IP, that always will be a valid ip address. + """ + behind_proxy = GlobalConfig.BEHIND_PROXY.getBool(False) + try: + request.ip = request.META['REMOTE_ADDR'] + except Exception: + logger.exception('Request ip not found!!') + request.ip = '' # No remote addr?? ... + + try: + proxies = request.META['HTTP_X_FORWARDED_FOR'].split(",") + request.ip_proxy = proxies[0] + + if not request.ip or behind_proxy: + # Request.IP will be None in case of nginx & gunicorn + # Some load balancers may include "domains" on x-forwarded for, + request.ip = request.ip_proxy.split('%')[0] # Stores the ip + + # will raise "list out of range", leaving ip_proxy = proxy in case of no other proxy apart of nginx + request.ip_proxy = proxies[1].strip() + except Exception: + request.ip_proxy = request.ip + + @staticmethod + def getUser(request: ExtendedHttpRequest) -> None: + """ + Ensures request user is the correct user + """ + user_id = request.session.get(USER_KEY) + user: typing.Optional[User] = None + if user_id: + try: + if user_id == ROOT_ID: + user = getRootUser() + else: + user = User.objects.get(pk=user_id) + except User.DoesNotExist: + user = None + + logger.debug('User at Middleware: %s %s', user_id, user) + + request.user = user diff --git a/server/src/uds/core/util/middleware/xua.py b/server/src/uds/core/util/middleware/xua.py new file mode 100644 index 00000000..4c5cb5c3 --- /dev/null +++ b/server/src/uds/core/util/middleware/xua.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013-2021 Virtual Cable S.L.U. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com +""" + +import logging + +from django.urls import reverse +from django.http import HttpResponseRedirect +from uds.core.util.config import GlobalConfig + +logger = logging.getLogger(__name__) + + +class XUACompatibleMiddleware: + """ + Add a X-UA-Compatible header to the response + This header tells to Internet Explorer to render page with latest + possible version or to use chrome frame if it is installed. + """ + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + response = self.get_response(request) + if response.get('content-type', '').startswith('text/html'): + response['X-UA-Compatible'] = 'IE=edge' + return response diff --git a/server/src/uds/core/util/request.py b/server/src/uds/core/util/request.py index ba5b0b7e..578c5d3f 100644 --- a/server/src/uds/core/util/request.py +++ b/server/src/uds/core/util/request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2012-2019 Virtual Cable S.L. +# Copyright (c) 2012-2021 Virtual Cable S.L.U. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, @@ -11,7 +11,7 @@ # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # @@ -35,17 +35,14 @@ import weakref import logging import typing -from django.http import HttpRequest, HttpResponse -from django.utils import timezone +from django.http import HttpRequest -from uds.core.util import os_detector as OsDetector from uds.core.util.tools import DictAsObj -from uds.core.util.config import GlobalConfig -from uds.core.auths.auth import EXPIRY_KEY, ROOT_ID, USER_KEY, getRootUser, webLogout from uds.models import User -# How often to check the requests cache for stuck objects -CHECK_SECONDS = 3600 * 24 # Once a day is more than enough +logger = logging.getLogger(__name__) + +_requests: typing.Dict[int, typing.Tuple[weakref.ref, datetime.datetime]] = {} class ExtendedHttpRequest(HttpRequest): @@ -59,11 +56,6 @@ class ExtendedHttpRequestWithUser(ExtendedHttpRequest): user: User -logger = logging.getLogger(__name__) - -_requests: typing.Dict[int, typing.Tuple[weakref.ref, datetime.datetime]] = {} - - def getIdent() -> int: ident = threading.current_thread().ident return ident if ident else -1 @@ -80,144 +72,36 @@ def getRequest() -> ExtendedHttpRequest: return ExtendedHttpRequest() +def delCurrentRequest() -> None: + ident = getIdent() + logger.debug('Deleting %s', ident) + try: + if ident in _requests: + del _requests[ident] # Remove stored request + else: + logger.info('Request id %s not stored in cache', ident) + except Exception: + logger.exception('Deleting stored request') -class UDSSessionMiddleware: - def __init__(self, get_response): - self.get_response = get_response - - -class GlobalRequestMiddleware: - lastCheck: typing.ClassVar[datetime.datetime] = datetime.datetime.now() - - def __init__(self, get_response: typing.Callable[[HttpRequest], HttpResponse]): - self._get_response: typing.Callable[[HttpRequest], HttpResponse] = get_response - - def _process_request(self, request: ExtendedHttpRequest) -> None: - # Store request on cache - - _requests[getIdent()] = ( - weakref.ref(typing.cast(ExtendedHttpRequest, request)), - datetime.datetime.now(), - ) - - # Add IP to request - GlobalRequestMiddleware.fillIps(request) - # Ensures request contains os - request.os = OsDetector.getOsFromUA( - request.META.get('HTTP_USER_AGENT', 'Unknown') - ) - # Ensures that requests contains the valid user - GlobalRequestMiddleware.getUser(request) - - def _process_response(self, request: ExtendedHttpRequest, response: HttpResponse): - # Remove IP from global cache (processing responses after this will make global request unavailable, - # but can be got from request again) - ident = getIdent() - logger.debug('Deleting %s', ident) +def cleanOldRequests() -> None: + logger.debug('Cleaning stuck requests from %s', _requests) + # No request lives 60 seconds, so 60 seconds is fine + cleanFrom: datetime.datetime = datetime.datetime.now() - datetime.timedelta( + seconds=60 + ) + toDelete: typing.List[int] = [] + for ident, request in _requests.items(): + if request[1] < cleanFrom: + toDelete.append(ident) + for ident in toDelete: try: - if ident in _requests: - del _requests[ident] # Remove stored request - else: - logger.info('Request id %s not stored in cache', ident) + del _requests[ident] except Exception: - logger.exception('Deleting stored request') + pass # Ignore it silently + - # Clean old stored if needed - GlobalRequestMiddleware.cleanStuckRequests() - - return response - - def __call__(self, request: ExtendedHttpRequest): - self._process_request(request) - - # Now, check if session is timed out... - if request.user: - # return HttpResponse(content='Session Expired', status=403, content_type='text/plain') - now = timezone.now() - expiry = request.session.get(EXPIRY_KEY, now) - if expiry < now: - webLogout( - request=request - ) # Ignore the response, just processes usere session logout - return HttpResponse(content='Session Expired', status=403) - # Update session timeout..self. - request.session[EXPIRY_KEY] = now + datetime.timedelta( - seconds=GlobalConfig.SESSION_DURATION_ADMIN.getInt() - if request.user.isStaff() - else GlobalConfig.SESSION_DURATION_USER.getInt() - ) - - response = self._get_response(request) - - return self._process_response(request, response) - - @staticmethod - def cleanStuckRequests() -> None: - # In case of some exception, keep clean very old request from time to time... - if ( - GlobalRequestMiddleware.lastCheck - > datetime.datetime.now() - datetime.timedelta(seconds=CHECK_SECONDS) - ): - return - logger.debug('Cleaning stuck requests from %s', _requests) - # No request lives 60 seconds, so 60 seconds is fine - cleanFrom: datetime.datetime = datetime.datetime.now() - datetime.timedelta( - seconds=60 - ) - toDelete: typing.List[int] = [] - for ident, request in _requests.items(): - if request[1] < cleanFrom: - toDelete.append(ident) - for ident in toDelete: - try: - del _requests[ident] - except Exception: - pass # Ignore it silently - - @staticmethod - def fillIps(request: ExtendedHttpRequest): - """ - Obtains the IP of a Django Request, even behind a proxy - - Returns the obtained IP, that always will be a valid ip address. - """ - behind_proxy = GlobalConfig.BEHIND_PROXY.getBool(False) - try: - request.ip = request.META['REMOTE_ADDR'] - except Exception: - logger.exception('Request ip not found!!') - request.ip = '' # No remote addr?? ... - - try: - proxies = request.META['HTTP_X_FORWARDED_FOR'].split(",") - request.ip_proxy = proxies[0] - - if not request.ip or behind_proxy: - # Request.IP will be None in case of nginx & gunicorn - # Some load balancers may include "domains" on x-forwarded for, - request.ip = request.ip_proxy.split('%')[0] # Stores the ip - - # will raise "list out of range", leaving ip_proxy = proxy in case of no other proxy apart of nginx - request.ip_proxy = proxies[1].strip() - except Exception: - request.ip_proxy = request.ip - - @staticmethod - def getUser(request: ExtendedHttpRequest) -> None: - """ - Ensures request user is the correct user - """ - user_id = request.session.get(USER_KEY) - user: typing.Optional[User] = None - if user_id: - try: - if user_id == ROOT_ID: - user = getRootUser() - else: - user = User.objects.get(pk=user_id) - except User.DoesNotExist: - user = None - - logger.debug('User at Middleware: %s %s', user_id, user) - - request.user = user +def setRequest(request: ExtendedHttpRequest): + _requests[getIdent()] = ( + weakref.ref(typing.cast(ExtendedHttpRequest, request)), + datetime.datetime.now(), + )