forked from shaba/openuds
Removing "globalRequest" cache and passing through received request object to authenticators
This commit is contained in:
parent
e999e5acf8
commit
590f3191ac
@ -176,7 +176,7 @@ class Login(Handler):
|
||||
password = 'xdaf44tgas4xd5ñasdłe4g€@#½|«ð2' # Extrange password if credential left empty. Value is not important, just not empty
|
||||
|
||||
logger.debug('Auth obj: %s', auth)
|
||||
user = authenticate(username, password, auth, True)
|
||||
user = authenticate(username, password, auth, self._request, True)
|
||||
if user is None: # invalid credentials
|
||||
# Sleep a while here to "prottect"
|
||||
time.sleep(3) # Wait 3 seconds if credentials fails for "protection"
|
||||
|
@ -38,10 +38,12 @@ from django.utils.translation import ugettext_noop as _
|
||||
from uds.core import auths
|
||||
from uds.core.util import net
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util.request import getRequest, ExtendedHttpRequest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
|
||||
|
||||
class IPAuth(auths.Authenticator):
|
||||
acceptProxy = gui.CheckBoxField(
|
||||
@ -52,15 +54,17 @@ class IPAuth(auths.Authenticator):
|
||||
'If checked, requests via proxy will get FORWARDED ip address'
|
||||
' (take care with this bein checked, can take internal IP addresses from internet)'
|
||||
),
|
||||
tab=gui.ADVANCED_TAB
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
visibleFromNets = gui.TextField(
|
||||
order=50,
|
||||
label=_('Visible only from this networks'),
|
||||
defvalue='',
|
||||
tooltip=_('This authenticator will be visible only from these networks. Leave empty to allow all networks'),
|
||||
tab=gui.ADVANCED_TAB
|
||||
tooltip=_(
|
||||
'This authenticator will be visible only from these networks. Leave empty to allow all networks'
|
||||
),
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
typeName = _('IP Authenticator')
|
||||
@ -75,8 +79,8 @@ class IPAuth(auths.Authenticator):
|
||||
|
||||
blockUserOnLoginFailures = False
|
||||
|
||||
def getIp(self) -> str:
|
||||
ip = getRequest().ip_proxy if self.acceptProxy.isTrue() else getRequest().ip
|
||||
def getIp(self, request: 'ExtendedHttpRequest') -> str:
|
||||
ip = request.ip_proxy if self.acceptProxy.isTrue() else request.ip
|
||||
logger.debug('Client IP: %s', ip)
|
||||
return ip
|
||||
|
||||
@ -90,9 +94,15 @@ class IPAuth(auths.Authenticator):
|
||||
except Exception as e:
|
||||
logger.error('Invalid network for IP auth: %s', e)
|
||||
|
||||
def authenticate(self, username: str, credentials: str, groupsManager: 'auths.GroupsManager') -> bool:
|
||||
def authenticate(
|
||||
self,
|
||||
username: str,
|
||||
credentials: str,
|
||||
groupsManager: 'auths.GroupsManager',
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> bool:
|
||||
# If credentials is a dict, that can't be sent directly from web interface, we allow entering
|
||||
if username == self.getIp():
|
||||
if username == self.getIp(request):
|
||||
self.getGroups(username, groupsManager)
|
||||
return True
|
||||
return False
|
||||
@ -106,11 +116,19 @@ class IPAuth(auths.Authenticator):
|
||||
return True
|
||||
return False
|
||||
|
||||
def internalAuthenticate(self, username: str, credentials: str, groupsManager: 'auths.GroupsManager') -> bool:
|
||||
def internalAuthenticate(
|
||||
self,
|
||||
username: str,
|
||||
credentials: str,
|
||||
groupsManager: 'auths.GroupsManager',
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> bool:
|
||||
# In fact, username does not matter, will get IP from request
|
||||
username = self.getIp() # Override provided username and use source IP
|
||||
username = self.getIp(request) # Override provided username and use source IP
|
||||
self.getGroups(username, groupsManager)
|
||||
if groupsManager.hasValidGroups() and self.dbAuthenticator().isValidUser(username, True):
|
||||
if groupsManager.hasValidGroups() and self.dbAuthenticator().isValidUser(
|
||||
username, True
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -124,7 +142,7 @@ class IPAuth(auths.Authenticator):
|
||||
def getJavascript(self, request: 'ExtendedHttpRequest') -> typing.Optional[str]:
|
||||
# We will authenticate ip here, from request.ip
|
||||
# If valid, it will simply submit form with ip submited and a cached generated random password
|
||||
ip = self.getIp()
|
||||
ip = self.getIp(request)
|
||||
gm = auths.GroupsManager(self.dbAuthenticator())
|
||||
self.getGroups(ip, gm)
|
||||
|
||||
@ -134,7 +152,9 @@ class IPAuth(auths.Authenticator):
|
||||
}}
|
||||
setVal("id_user", "{ip}");
|
||||
setVal("id_password", "{passwd}");
|
||||
document.getElementById("loginform").submit();'''.format(ip=ip, passwd='')
|
||||
document.getElementById("loginform").submit();'''.format(
|
||||
ip=ip, passwd=''
|
||||
)
|
||||
|
||||
return 'alert("invalid authhenticator"); window.location.reload();'
|
||||
|
||||
|
@ -43,12 +43,12 @@ from uds.core import auths
|
||||
from uds.core.ui import gui
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core.util.state import State
|
||||
from uds.core.util.request import getRequest
|
||||
from uds.core.auths.auth import authLogLogin
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds import models
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -92,22 +92,13 @@ class InternalDBAuth(auths.Authenticator):
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
def getIp(self) -> str:
|
||||
ip = (
|
||||
getRequest().ip_proxy if self.acceptProxy.isTrue() else getRequest().ip
|
||||
) # pylint: disable=maybe-no-member
|
||||
if self.reverseDns.isTrue():
|
||||
try:
|
||||
return str(
|
||||
dns.resolver.query(dns.reversename.from_address(ip), 'PTR')[0]
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
return ip
|
||||
|
||||
def transformUsername(self, username: str) -> str:
|
||||
def transformUsername(self, username: str, request: 'ExtendedHttpRequest') -> str:
|
||||
if self.differentForEachHost.isTrue():
|
||||
newUsername = self.getIp() + '-' + username
|
||||
newUsername = (
|
||||
(request.ip_proxy if self.acceptProxy.isTrue() else request.ip)
|
||||
+ '-'
|
||||
+ username
|
||||
)
|
||||
# Duplicate basic user into username.
|
||||
auth = self.dbAuthenticator()
|
||||
# "Derived" users will belong to no group at all, because we will extract groups from "base" user
|
||||
@ -129,14 +120,18 @@ class InternalDBAuth(auths.Authenticator):
|
||||
return username
|
||||
|
||||
def authenticate(
|
||||
self, username: str, credentials: str, groupsManager: 'auths.GroupsManager'
|
||||
self,
|
||||
username: str,
|
||||
credentials: str,
|
||||
groupsManager: 'auths.GroupsManager',
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> bool:
|
||||
logger.debug('Username: %s, Password: %s', username, credentials)
|
||||
dbAuth = self.dbAuthenticator()
|
||||
try:
|
||||
user: 'models.User' = dbAuth.users.get(name=username, state=State.ACTIVE)
|
||||
except Exception:
|
||||
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid user')
|
||||
authLogLogin(request, self.dbAuthenticator(), username, 'Invalid user')
|
||||
return False
|
||||
|
||||
if user.parent: # Direct auth not allowed for "derived" users
|
||||
@ -146,7 +141,8 @@ class InternalDBAuth(auths.Authenticator):
|
||||
if cryptoManager().checkHash(credentials, user.password):
|
||||
groupsManager.validate([g.name for g in user.groups.all()])
|
||||
return True
|
||||
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid password')
|
||||
|
||||
authLogLogin(request, self.dbAuthenticator(), username, 'Invalid password')
|
||||
return False
|
||||
|
||||
def getGroups(self, username: str, groupsManager: 'auths.GroupsManager'):
|
||||
|
@ -39,12 +39,11 @@ from uds.core.ui import gui
|
||||
from uds.core import auths
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core.auths.auth import authLogLogin
|
||||
from uds.core.util.request import getRequest
|
||||
|
||||
from . import client
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
pass
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -116,8 +115,8 @@ class RadiusAuth(auths.Authenticator):
|
||||
def initialize(self, values: typing.Optional[typing.Dict[str, typing.Any]]) -> None:
|
||||
pass
|
||||
|
||||
def radiusClient(self) -> client.RadiusClient:
|
||||
""" Return a new radius client . """
|
||||
def radiusClient(self) -> client.RadiusClient:
|
||||
"""Return a new radius client ."""
|
||||
return client.RadiusClient(
|
||||
self.server.value,
|
||||
self.secret.value.encode(),
|
||||
@ -126,13 +125,22 @@ class RadiusAuth(auths.Authenticator):
|
||||
)
|
||||
|
||||
def authenticate(
|
||||
self, username: str, credentials: str, groupsManager: 'auths.GroupsManager'
|
||||
self,
|
||||
username: str,
|
||||
credentials: str,
|
||||
groupsManager: 'auths.GroupsManager',
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> bool:
|
||||
try:
|
||||
connection = self.radiusClient()
|
||||
groups = connection.authenticate(username=username, password=credentials)
|
||||
except Exception:
|
||||
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Access denied by Raiuds')
|
||||
authLogLogin(
|
||||
request,
|
||||
self.dbAuthenticator(),
|
||||
username,
|
||||
'Access denied by Raiuds',
|
||||
)
|
||||
return False
|
||||
|
||||
if self.globalGroup.value.strip():
|
||||
@ -161,23 +169,23 @@ class RadiusAuth(auths.Authenticator):
|
||||
return super().removeUser(username)
|
||||
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
""" Test the connection to the server . """
|
||||
def test(env, data):
|
||||
"""Test the connection to the server ."""
|
||||
try:
|
||||
auth = RadiusAuth(None, env, data) # type: ignore
|
||||
return auth.testConnection()
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Exception found testing Radius auth %s: %s", e.__class__, e
|
||||
)
|
||||
logger.error("Exception found testing Radius auth %s: %s", e.__class__, e)
|
||||
return [False, _('Error testing connection')]
|
||||
|
||||
def testConnection(self):
|
||||
""" Test connection to Radius Server """
|
||||
def testConnection(self):
|
||||
"""Test connection to Radius Server"""
|
||||
try:
|
||||
connection = self.radiusClient()
|
||||
# Reply is not important...
|
||||
connection.authenticate(cryptoManager().randomString(10), cryptoManager().randomString(10))
|
||||
connection.authenticate(
|
||||
cryptoManager().randomString(10), cryptoManager().randomString(10)
|
||||
)
|
||||
except client.RadiusAuthenticationError as e:
|
||||
pass
|
||||
except Exception:
|
||||
|
@ -43,7 +43,6 @@ from uds.core import auths
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import ldaputil
|
||||
from uds.core.auths.auth import authLogLogin
|
||||
from uds.core.util.request import getRequest
|
||||
|
||||
try:
|
||||
# pylint: disable=no-name-in-module
|
||||
@ -53,8 +52,8 @@ except Exception:
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.http import HttpRequest # pylint: disable=ungrouped-imports
|
||||
from uds.core.environment import Environment
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
from uds import models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -485,7 +484,11 @@ class RegexLdap(auths.Authenticator):
|
||||
return ' '.join(self.__processField(self._userNameAttr, user))
|
||||
|
||||
def authenticate(
|
||||
self, username: str, credentials: str, groupsManager: 'auths.GroupsManager'
|
||||
self,
|
||||
username: str,
|
||||
credentials: str,
|
||||
groupsManager: 'auths.GroupsManager',
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> bool:
|
||||
"""
|
||||
Must authenticate the user.
|
||||
@ -502,7 +505,7 @@ class RegexLdap(auths.Authenticator):
|
||||
|
||||
if usr is None:
|
||||
authLogLogin(
|
||||
getRequest(), self.dbAuthenticator(), username, 'Invalid user'
|
||||
request, self.dbAuthenticator(), username, 'Invalid user'
|
||||
)
|
||||
return False
|
||||
|
||||
@ -513,7 +516,7 @@ class RegexLdap(auths.Authenticator):
|
||||
) # Will raise an exception if it can't connect
|
||||
except:
|
||||
authLogLogin(
|
||||
getRequest(), self.dbAuthenticator(), username, 'Invalid password'
|
||||
request, self.dbAuthenticator(), username, 'Invalid password'
|
||||
)
|
||||
return False
|
||||
|
||||
|
@ -42,11 +42,10 @@ from uds.core.ui import gui
|
||||
from uds.core import auths
|
||||
from uds.core.util import ldaputil
|
||||
from uds.core.auths.auth import authLogLogin
|
||||
from uds.core.util.request import getRequest
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.http import HttpRequest # pylint: disable=ungrouped-imports
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -385,7 +384,7 @@ class SimpleLDAPAuthenticator(auths.Authenticator):
|
||||
).strip()
|
||||
|
||||
def authenticate(
|
||||
self, username: str, credentials: str, groupsManager: 'auths.GroupsManager'
|
||||
self, username: str, credentials: str, groupsManager: 'auths.GroupsManager', request: 'ExtendedHttpRequest'
|
||||
) -> bool:
|
||||
'''
|
||||
Must authenticate the user.
|
||||
@ -402,7 +401,7 @@ class SimpleLDAPAuthenticator(auths.Authenticator):
|
||||
|
||||
if user is None:
|
||||
authLogLogin(
|
||||
getRequest(), self.dbAuthenticator(), username, 'Invalid user'
|
||||
request, self.dbAuthenticator(), username, 'Invalid user'
|
||||
)
|
||||
return False
|
||||
|
||||
@ -413,7 +412,7 @@ class SimpleLDAPAuthenticator(auths.Authenticator):
|
||||
) # Will raise an exception if it can't connect
|
||||
except:
|
||||
authLogLogin(
|
||||
getRequest(), self.dbAuthenticator(), username, 'Invalid password'
|
||||
request, self.dbAuthenticator(), username, 'Invalid password'
|
||||
)
|
||||
return False
|
||||
|
||||
|
@ -202,20 +202,19 @@ def denyNonAuthenticated(
|
||||
|
||||
|
||||
def __registerUser(
|
||||
authenticator: Authenticator, authInstance: AuthenticatorInstance, username: str
|
||||
authenticator: Authenticator,
|
||||
authInstance: AuthenticatorInstance,
|
||||
username: str,
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> typing.Optional[User]:
|
||||
"""
|
||||
Check if this user already exists on database with this authenticator, if don't, create it with defaults
|
||||
This will work correctly with both internal or externals cause we first authenticate the user, if internal and user do not exists in database
|
||||
authenticate will return false, if external and return true, will create a reference in database
|
||||
"""
|
||||
from uds.core.util.request import getRequest
|
||||
|
||||
username = authInstance.transformUsername(username)
|
||||
username = authInstance.transformUsername(username, request)
|
||||
logger.debug('Transformed username: %s', username)
|
||||
|
||||
request = getRequest()
|
||||
|
||||
usr = authenticator.getOrCreateUser(username, username)
|
||||
usr.real_name = authInstance.getRealName(username)
|
||||
usr.save()
|
||||
@ -242,6 +241,7 @@ def authenticate(
|
||||
username: str,
|
||||
password: str,
|
||||
authenticator: Authenticator,
|
||||
request: 'ExtendedHttpRequest',
|
||||
useInternalAuthenticate: bool = False,
|
||||
) -> typing.Optional[User]:
|
||||
"""
|
||||
@ -249,6 +249,7 @@ def authenticate(
|
||||
@param username: username to authenticate
|
||||
@param password: password to authenticate this user
|
||||
@param authenticator: Authenticator (database object) used to authenticate with provided credentials
|
||||
@param request: Request object
|
||||
@param useInternalAuthenticate: If True, tries to authenticate user using "internalAuthenticate". If false, it uses "authenticate".
|
||||
This is so because in some situations we may want to use a "trusted" method (internalAuthenticate is never invoked directly from web)
|
||||
@return: None if authentication fails, User object (database object) if authentication is o.k.
|
||||
@ -269,9 +270,9 @@ def authenticate(
|
||||
gm = auths.GroupsManager(authenticator)
|
||||
authInstance = authenticator.getInstance()
|
||||
if useInternalAuthenticate is False:
|
||||
res = authInstance.authenticate(username, password, gm)
|
||||
res = authInstance.authenticate(username, password, gm, request)
|
||||
else:
|
||||
res = authInstance.internalAuthenticate(username, password, gm)
|
||||
res = authInstance.internalAuthenticate(username, password, gm, request)
|
||||
|
||||
if res is False:
|
||||
return None
|
||||
@ -286,11 +287,13 @@ def authenticate(
|
||||
)
|
||||
return None
|
||||
|
||||
return __registerUser(authenticator, authInstance, username)
|
||||
return __registerUser(authenticator, authInstance, username, request)
|
||||
|
||||
|
||||
def authenticateViaCallback(
|
||||
authenticator: Authenticator, params: typing.Any, request: 'ExtendedHttpRequestWithUser'
|
||||
authenticator: Authenticator,
|
||||
params: typing.Any,
|
||||
request: 'ExtendedHttpRequestWithUser',
|
||||
) -> typing.Optional[User]:
|
||||
"""
|
||||
Given an username, this method will get invoked whenever the url for a callback
|
||||
@ -322,7 +325,7 @@ def authenticateViaCallback(
|
||||
if username is None or username == '' or gm.hasValidGroups() is False:
|
||||
raise auths.exceptions.InvalidUserException('User doesn\'t has access to UDS')
|
||||
|
||||
return __registerUser(authenticator, authInstance, username)
|
||||
return __registerUser(authenticator, authInstance, username, request)
|
||||
|
||||
|
||||
def authCallbackUrl(authenticator: Authenticator) -> str:
|
||||
|
@ -44,7 +44,7 @@ if typing.TYPE_CHECKING:
|
||||
HttpResponse,
|
||||
) # pylint: disable=ungrouped-imports
|
||||
from uds.core.environment import Environment
|
||||
from uds.core.util.request import ExtendedHttpRequestWithUser
|
||||
from uds.core.util.request import ExtendedHttpRequestWithUser, ExtendedHttpRequest
|
||||
from uds import models
|
||||
from .groups_manager import GroupsManager
|
||||
|
||||
@ -292,7 +292,7 @@ class Authenticator(Module): # pylint: disable=too-many-public-methods
|
||||
return []
|
||||
|
||||
def authenticate(
|
||||
self, username: str, credentials: str, groupsManager: 'GroupsManager'
|
||||
self, username: str, credentials: str, groupsManager: 'GroupsManager', request: 'ExtendedHttpRequest'
|
||||
) -> bool:
|
||||
"""
|
||||
This method must be overriden, and is responsible for authenticating
|
||||
@ -340,7 +340,7 @@ class Authenticator(Module): # pylint: disable=too-many-public-methods
|
||||
"""
|
||||
return True
|
||||
|
||||
def transformUsername(self, username: str) -> str:
|
||||
def transformUsername(self, username: str, request: 'ExtendedHttpRequest') -> str:
|
||||
"""
|
||||
On login, this method get called so we can "transform" provided user name.
|
||||
|
||||
@ -356,7 +356,7 @@ class Authenticator(Module): # pylint: disable=too-many-public-methods
|
||||
return username
|
||||
|
||||
def internalAuthenticate(
|
||||
self, username: str, credentials: str, groupsManager: 'GroupsManager'
|
||||
self, username: str, credentials: str, groupsManager: 'GroupsManager', request: 'ExtendedHttpRequest'
|
||||
) -> bool:
|
||||
"""
|
||||
This method is provided so "plugins" (For example, a custom dispatcher), can test
|
||||
@ -391,7 +391,7 @@ class Authenticator(Module): # pylint: disable=too-many-public-methods
|
||||
This is done in this way, because UDS has only a subset of groups for this user, and
|
||||
we let the authenticator decide inside wich groups of UDS this users is included.
|
||||
"""
|
||||
return self.authenticate(username, credentials, groupsManager)
|
||||
return self.authenticate(username, credentials, groupsManager, request)
|
||||
|
||||
def logout(self, username: str) -> typing.Optional[str]:
|
||||
"""
|
||||
@ -486,7 +486,7 @@ class Authenticator(Module): # pylint: disable=too-many-public-methods
|
||||
self,
|
||||
parameters: typing.Dict[str, typing.Any],
|
||||
gm: 'GroupsManager',
|
||||
request: 'ExtendedHttpRequestWithUser',
|
||||
request: 'ExtendedHttpRequest',
|
||||
) -> typing.Optional[str]:
|
||||
"""
|
||||
There is a view inside UDS, an url, that will redirect the petition
|
||||
|
@ -39,14 +39,12 @@ 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
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# How often to check the requests cache for stuck objects
|
||||
@ -59,22 +57,16 @@ class GlobalRequestMiddleware:
|
||||
def __init__(self, get_response: typing.Callable[[HttpRequest], HttpResponse]):
|
||||
self._get_response: typing.Callable[[HttpRequest], HttpResponse] = get_response
|
||||
|
||||
def _process_response(self, request: ExtendedHttpRequest, response: HttpResponse):
|
||||
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):
|
||||
def __call__(self, request: 'ExtendedHttpRequest'):
|
||||
# Add IP to request
|
||||
GlobalRequestMiddleware.fillIps(request)
|
||||
|
||||
# Store request on cache
|
||||
setRequest(request=request)
|
||||
|
||||
# Ensures request contains os
|
||||
request.os = OsDetector.getOsFromUA(
|
||||
request.META.get('HTTP_USER_AGENT', 'Unknown')
|
||||
@ -105,17 +97,7 @@ class GlobalRequestMiddleware:
|
||||
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):
|
||||
def fillIps(request: 'ExtendedHttpRequest'):
|
||||
"""
|
||||
Obtains the IP of a Django Request, even behind a proxy
|
||||
|
||||
@ -161,7 +143,7 @@ class GlobalRequestMiddleware:
|
||||
logger.debug('ip: %s, ip_proxy: %s', request.ip, request.ip_proxy)
|
||||
|
||||
@staticmethod
|
||||
def getUser(request: ExtendedHttpRequest) -> None:
|
||||
def getUser(request: 'ExtendedHttpRequest') -> None:
|
||||
"""
|
||||
Ensures request user is the correct user
|
||||
"""
|
||||
|
@ -59,69 +59,3 @@ class ExtendedHttpRequest(HttpRequest):
|
||||
class ExtendedHttpRequestWithUser(ExtendedHttpRequest):
|
||||
user: User
|
||||
|
||||
|
||||
identity_context: contextvars.ContextVar[int] = contextvars.ContextVar('identity')
|
||||
|
||||
# Return an unique id for the current running thread or the current running coroutine
|
||||
def getIdent() -> int:
|
||||
# Defect if we are on a thread or on asyncio
|
||||
try:
|
||||
if asyncio.get_event_loop().is_running():
|
||||
if identity_context.get(None) is None:
|
||||
identity_context.set(
|
||||
# Generate a really unique random number for the asyncio task based on current time
|
||||
# lower 16 are random, upper bits are based on current time
|
||||
random.randint(0, 2 ** 16 - 1)
|
||||
+ int(datetime.datetime.now().timestamp()) * 2 ** 16
|
||||
) # Every "task" has its own context
|
||||
return identity_context.get()
|
||||
except Exception:
|
||||
pass
|
||||
return threading.current_thread().ident or -1
|
||||
|
||||
|
||||
def getRequest() -> ExtendedHttpRequest:
|
||||
ident = getIdent()
|
||||
val = (
|
||||
typing.cast(typing.Optional[ExtendedHttpRequest], _requests[ident][0]())
|
||||
if ident in _requests
|
||||
else None
|
||||
) # Return obj from weakref
|
||||
|
||||
return val or 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')
|
||||
|
||||
|
||||
def cleanOldRequests() -> None:
|
||||
logger.debug('Cleaning stuck requests from %s', _requests)
|
||||
# No request lives 3600 seconds, so 3600 seconds is fine
|
||||
cleanFrom: datetime.datetime = datetime.datetime.now() - datetime.timedelta(
|
||||
seconds=3600
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
def setRequest(request: ExtendedHttpRequest):
|
||||
_requests[getIdent()] = (
|
||||
weakref.ref(typing.cast(ExtendedHttpRequest, request)),
|
||||
datetime.datetime.now(),
|
||||
)
|
||||
|
@ -124,7 +124,7 @@ def checkLogin( # pylint: disable=too-many-branches, too-many-statements
|
||||
user = None
|
||||
if password == '':
|
||||
password = 'axd56adhg466jasd6q8sadñ€sáé--v' # Random string, in fact, just a placeholder that will not be used :)
|
||||
user = authenticate(userName, password, authenticator)
|
||||
user = authenticate(userName, password, authenticator, request=request)
|
||||
logger.debug('User: %s', user)
|
||||
|
||||
if user is None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user