Last active
December 19, 2015 21:58
-
-
Save jneight/6023834 to your computer and use it in GitHub Desktop.
For tastypie. Middleware to logs all requests. Store the params used in POST and PUT applying a sensitive word substitution.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf-8 | |
import datetime | |
import logging | |
logger = logging.getLogger('djangoapp') | |
from django.views.debug import CLEANSED_SUBSTITUTE | |
from django.conf import settings | |
from tastypie.utils.mime import determine_format | |
from tastypie.exceptions import UnsupportedFormat | |
from tastypie.serializers import JSONSerializer | |
SENSITIVE_PARAMS = [ | |
'password', 'old_password',] | |
SENSITIVE_HEADERS = ['Authorization', 'HTTP_AUTHORIZATION'] | |
class ResponseLoggingMiddleware(object): | |
def process_response(self, request, response): | |
if hasattr(request, 'user') and request.user.is_authenticated(): | |
credentials = request.user.pk | |
else: | |
credentials = -1 | |
serializer = JSONSerializer() | |
format = determine_format( | |
request, serializer, default_format='application/json') | |
# clean POST received from client | |
if request.method in ['POST', 'PUT']: | |
try: | |
cleansed = serializer.deserialize( | |
request.body, | |
format=format) | |
except ValueError: | |
cleansed = request.POST.dict() | |
except UnsupportedFormat: | |
cleansed = 'UNSUPPORTED_FORMAT' | |
except AttributeError: | |
cleansed = 'UNSUPPORTED_STRING' | |
except Exception as e: | |
logger.warning( | |
u"[RESPONSE] %(c)s: %(e)s", | |
{'c': e.__class__, 'e': e}) | |
cleansed = 'STRING' | |
finally: | |
if hasattr(cleansed, 'keys'): | |
cleansed.update( | |
dict( | |
(param, CLEANSED_SUBSTITUTE) | |
for param in SENSITIVE_PARAMS | |
if param in cleansed)) | |
else: | |
cleansed = 'STRING' | |
# clean response sent to client | |
if response.content and settings.FULL_RESPONSE_LOGGING: | |
try: | |
content = serializer.deserialize( | |
response.content, | |
format=format) | |
content.update( | |
dict( | |
(param, CLEANSED_SUBSTITUTE) | |
for param in SENSITIVE_PARAMS | |
if param in content)) | |
except AttributeError: | |
content = 'UNSUPPORTED_STRING' | |
except (UnsupportedFormat, ValueError): | |
content = 'UNSUPPORTED_FORMAT' | |
else: | |
content = 'HIDDEN' | |
# clean headers from client | |
if settings.FULL_HEADER_LOGGING: | |
cleansed_headers = getattr(request, 'META', {}) | |
cleansed_headers.update( | |
dict( | |
(param, CLEANSED_SUBSTITUTE) | |
for param in SENSITIVE_HEADERS | |
if param in cleansed_headers)) | |
else: | |
cleansed_headers = '' | |
if 'HTTP_X_FORWARDED_FOR' in request.META: | |
ip = request.META['HTTP_X_FORWARDED_FOR'].split(",")[0] | |
else: | |
ip = request.META['REMOTE_ADDR'] | |
logger.info( | |
u"[ACCESS] %(h)s %(l)s user=%(u)s - %(t)s \"%(r)s\" status=%(s)s " | |
u"%(b)s - \"%(f)s\" - \"%(a)s\" - data=%(i)s - headers=%(j)s -" | |
u"content=%(o)s", | |
{ | |
'h': ip, | |
'l': '-', | |
'u': credentials, | |
't': datetime.datetime.now(), | |
'r': '%s %s' % (request.method, request.get_full_path()), | |
's': response.status_code, | |
'b': request.META.get('CONTENT_LENGTH', ''), | |
'f': request.META.get('HTTP_REFERER', ''), | |
'a': request.META.get( | |
'HTTP_USER_AGENT', '').decode('utf-8', 'replace'), | |
'i': cleansed, | |
'o': content, | |
'j': cleansed_headers} | |
) | |
return response |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment