mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Use a middleware rather than inspect the stack to get current user and IP
This commit is contained in:
		
							
								
								
									
										55
									
								
								apps/logs/middlewares.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								apps/logs/middlewares.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.contrib.auth.models import AnonymousUser
 | 
			
		||||
from threading import local
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
USER_ATTR_NAME = getattr(settings, 'LOCAL_USER_ATTR_NAME', '_current_user')
 | 
			
		||||
IP_ATTR_NAME = getattr(settings, 'LOCAL_IP_ATTR_NAME', '_current_ip')
 | 
			
		||||
 | 
			
		||||
_thread_locals = local()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _set_current_user_and_ip(user=None, ip=None):
 | 
			
		||||
    """
 | 
			
		||||
    Sets current user in local thread.
 | 
			
		||||
    Can be used as a hook e.g. for shell jobs (when request object is not
 | 
			
		||||
    available).
 | 
			
		||||
    """
 | 
			
		||||
    setattr(_thread_locals, USER_ATTR_NAME, user)
 | 
			
		||||
    setattr(_thread_locals, IP_ATTR_NAME, ip)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_current_user():
 | 
			
		||||
    return getattr(_thread_locals, USER_ATTR_NAME, None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_current_ip():
 | 
			
		||||
    return getattr(_thread_locals, IP_ATTR_NAME, None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_current_authenticated_user():
 | 
			
		||||
    current_user = get_current_user()
 | 
			
		||||
    if isinstance(current_user, AnonymousUser):
 | 
			
		||||
        return None
 | 
			
		||||
    return current_user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LogsMiddleware(object):
 | 
			
		||||
    def __init__(self, get_response):
 | 
			
		||||
        self.get_response = get_response
 | 
			
		||||
 | 
			
		||||
    def __call__(self, request):
 | 
			
		||||
        user = request.user
 | 
			
		||||
        if 'HTTP_X_FORWARDED_FOR' in request.META:
 | 
			
		||||
            ip = request.META.get('HTTP_X_FORWARDED_FOR')
 | 
			
		||||
        else:
 | 
			
		||||
            ip = request.META.get('REMOTE_ADDR')
 | 
			
		||||
 | 
			
		||||
        _set_current_user_and_ip(user, ip)
 | 
			
		||||
 | 
			
		||||
        response = self.get_response(request)
 | 
			
		||||
 | 
			
		||||
        return response
 | 
			
		||||
@@ -1,48 +1,15 @@
 | 
			
		||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
import inspect
 | 
			
		||||
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.core import serializers
 | 
			
		||||
from django.db.models.signals import pre_save, post_save, post_delete
 | 
			
		||||
from django.dispatch import receiver
 | 
			
		||||
 | 
			
		||||
from .middlewares import get_current_authenticated_user, get_current_ip
 | 
			
		||||
from .models import Changelog
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_request_in_signal(sender):
 | 
			
		||||
    req = None
 | 
			
		||||
    for entry in reversed(inspect.stack()):
 | 
			
		||||
        try:
 | 
			
		||||
            req = entry[0].f_locals['request']
 | 
			
		||||
            # Check if there is a user
 | 
			
		||||
            # noinspection PyStatementEffect
 | 
			
		||||
            req.user
 | 
			
		||||
            break
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
    if not req:
 | 
			
		||||
        print("WARNING: Attempt to save " + str(sender) + " with no user")
 | 
			
		||||
 | 
			
		||||
    return req
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_user_and_ip(sender):
 | 
			
		||||
    req = get_request_in_signal(sender)
 | 
			
		||||
    try:
 | 
			
		||||
        user = req.user
 | 
			
		||||
        if 'HTTP_X_FORWARDED_FOR' in req.META:
 | 
			
		||||
            ip = req.META.get('HTTP_X_FORWARDED_FOR')
 | 
			
		||||
        else:
 | 
			
		||||
            ip = req.META.get('REMOTE_ADDR')
 | 
			
		||||
    except:
 | 
			
		||||
        user = None
 | 
			
		||||
        ip = None
 | 
			
		||||
    return user, ip
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EXCLUDED = [
 | 
			
		||||
    'admin.logentry',
 | 
			
		||||
    'authtoken.token',
 | 
			
		||||
@@ -75,13 +42,11 @@ def save_object(sender, instance, **kwargs):
 | 
			
		||||
    if instance._meta.label_lower in EXCLUDED:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    print("LOGGING SOMETHING")
 | 
			
		||||
 | 
			
		||||
    previous = instance._previous
 | 
			
		||||
 | 
			
		||||
    user, ip = get_user_and_ip(sender)
 | 
			
		||||
 | 
			
		||||
    from django.contrib.auth.models import AnonymousUser
 | 
			
		||||
    if isinstance(user, AnonymousUser):
 | 
			
		||||
        user = None
 | 
			
		||||
    user, ip = get_current_authenticated_user(), get_current_ip()
 | 
			
		||||
 | 
			
		||||
    if user is not None and instance._meta.label_lower == "auth.user" and previous:
 | 
			
		||||
        # Don't save last login modifications
 | 
			
		||||
@@ -111,7 +76,7 @@ def delete_object(sender, instance, **kwargs):
 | 
			
		||||
    if instance._meta.label_lower in EXCLUDED:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    user, ip = get_user_and_ip(sender)
 | 
			
		||||
    user, ip = get_current_authenticated_user(), get_current_ip()
 | 
			
		||||
 | 
			
		||||
    instance_json = serializers.serialize('json', [instance, ])[1:-1]
 | 
			
		||||
    Changelog.objects.create(user=user,
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,11 @@ if "cas" in INSTALLED_APPS:
 | 
			
		||||
        'cas_explained',
 | 
			
		||||
    ]
 | 
			
		||||
    AUTHENTICATION_BACKENDS += ('cas.backends.CASBackend',)
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if "logs" in INSTALLED_APPS:
 | 
			
		||||
    MIDDLEWARE += ('logs.middlewares.LogsMiddleware',)
 | 
			
		||||
 | 
			
		||||
if "debug_toolbar" in INSTALLED_APPS:
 | 
			
		||||
    MIDDLEWARE.insert(1,"debug_toolbar.middleware.DebugToolbarMiddleware")
 | 
			
		||||
    INTERNAL_IPS = [ '127.0.0.1']
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user