Skip to content

Commit

Permalink
merge with django-see-profile
Browse files Browse the repository at this point in the history
  • Loading branch information
SunnyR committed Jun 6, 2024
1 parent fcb6015 commit 618f42e
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 37 deletions.
79 changes: 43 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,76 +54,83 @@ Provided middleware modules will modify web application's output and input and i
or minimum configuration.

<table>

<tr>
<th>Middleware</th>
<th>Description</th>
<th>Configuration</th>
</tr>

<tr>
<th>Middleware
<th>Description
<th>Configuration
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ClearSiteDataMiddleware">ClearSiteDataMiddleware</a></td>
<td>Send Clear-Site-Data header in HTTP response for any page that has been whitelisted. <em>Recommended</em>.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ClearSiteDataMiddleware">ClearSiteDataMiddleware</a>
<td>Send Clear-Site-Data header in HTTP response for any page that has been whitelisted. <em>Recommended</em>.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ContentSecurityPolicyMiddleware">ContentSecurityPolicyMiddleware</a></td>
<td>Send Content Security Policy (CSP) header in HTTP response. <em>Recommended,</em> requires careful tuning.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ContentSecurityPolicyMiddleware">ContentSecurityPolicyMiddleware</a>
<td>Send Content Security Policy (CSP) header in HTTP response. <em>Recommended,</em> requires careful tuning.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.DoNotTrackMiddleware">DoNotTrackMiddleware</a></td>
<td>Read user browser's DoNotTrack preference and pass it to application. <em>Recommended,</em> requires implementation in views and templates.</td>
<td>None.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.DoNotTrackMiddleware">DoNotTrackMiddleware</a>
<td>Read user browser's DoNotTrack preference and pass it to application. <em>Recommended,</em> requires implementation in views and templates.
<td>None.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.LoginRequiredMiddleware">LoginRequiredMiddleware</a></td>
<td>Requires a user to be authenticated to view any page on the site that hasn't been white listed.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.LoginRequiredMiddleware">LoginRequiredMiddleware</a>
<td>Requires a user to be authenticated to view any page on the site that hasn't been white listed.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.MandatoryPasswordChangeMiddleware">MandatoryPasswordChangeMiddleware</a></td>
<td>Redirects any request from an authenticated user to the password change form if that user's password has expired.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.MandatoryPasswordChangeMiddleware">MandatoryPasswordChangeMiddleware</a>
<td>Redirects any request from an authenticated user to the password change form if that user's password has expired.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.NoConfidentialCachingMiddleware">NoConfidentialCachingMiddleware</a></td>
<td>Adds No-Cache and No-Store headers to confidential pages.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.NoConfidentialCachingMiddleware">NoConfidentialCachingMiddleware</a>
<td>Adds No-Cache and No-Store headers to confidential pages.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.P3PPolicyMiddleware">P3PPolicyMiddleware</a></td>
<td><b>DEPRECATED: </b>Will be removed in future releases.<br/>Adds the HTTP header attribute specifying compact P3P policy.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.P3PPolicyMiddleware">P3PPolicyMiddleware</a>
<td><b>DEPRECATED: </b>Will be removed in future releases.<br/>Adds the HTTP header attribute specifying compact P3P policy.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ReferrerPolicyMiddleware">ReferrerPolicyMiddleware</a></td>
<td>Specify when the browser will set a `Referer` header.</td>
<td>Optional.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ReferrerPolicyMiddleware">ReferrerPolicyMiddleware</a>
<td>Specify when the browser will set a `Referer` header.
<td>Optional.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.SessionExpiryPolicyMiddleware">SessionExpiryPolicyMiddleware</a></td>
<td>Expire sessions on browser close, and on expiry times stored in the cookie itself.</td>
<td>Required.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.SessionExpiryPolicyMiddleware">SessionExpiryPolicyMiddleware</a>
<td>Expire sessions on browser close, and on expiry times stored in the cookie itself.
<td>Required.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.StrictTransportSecurityMiddleware">StrictTransportSecurityMiddleware</a></td>
<td><b>DEPRECATED: </b>Will be removed in future releases, consider <a href="https://docs.djangoproject.com/en/1.11/ref/middleware/#django.middleware.security.SecurityMiddleware">django.middleware.security.SecurityMiddleware</a> via <i>SECURE_HSTS_SECONDS</i>, <i>SECURE_HSTS_INCLUDE_SUBDOMAINS</i> and <i>SECURE_HSTS_PRELOAD</i> settings.<br/>Enforce SSL/TLS connection and disable plaintext fall-back. <em>Recommended</em> for SSL/TLS sites.</td>
<td>Optional.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.StrictTransportSecurityMiddleware">StrictTransportSecurityMiddleware</a>
<td><b>DEPRECATED: </b>Will be removed in future releases, consider <a href="https://docs.djangoproject.com/en/1.11/ref/middleware/#django.middleware.security.SecurityMiddleware">django.middleware.security.SecurityMiddleware</a> via <i>SECURE_HSTS_SECONDS</i>, <i>SECURE_HSTS_INCLUDE_SUBDOMAINS</i> and <i>SECURE_HSTS_PRELOAD</i> settings.<br/>Enforce SSL/TLS connection and disable plaintext fall-back. <em>Recommended</em> for SSL/TLS sites.
<td>Optional.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.XFrameOptionsMiddleware">XFrameOptionsMiddleware</a></td>
<td>Disable framing of the website, mitigating Clickjacking attacks. <em>Recommended.</em></td>
<td>Optional.</td>
</tr>

<tr>
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.XFrameOptionsMiddleware">XFrameOptionsMiddleware</a>
<td>Disable framing of the website, mitigating Clickjacking attacks. <em>Recommended.</em>
<td>Optional.
<td><a href="http://django-security.readthedocs.org/en/latest/#security.middleware.ProfilingMiddleware">ProfilingMiddleware</a></td>
<td>A simple middleware to capture useful profiling information in Django.</td>
<td>Optional.</td>
</tr>

</table>
Expand Down
93 changes: 92 additions & 1 deletion security/middleware.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
# Copyright (c) 2011, SD Elements. See LICENSE.txt for details.

import cProfile
import importlib
import json
import logging
import pstats
import warnings
from io import StringIO
from re import compile

import dateutil.parser
import django.conf
import django.views.static
import sqlparse
from django.contrib.auth import logout
from django.core.exceptions import ImproperlyConfigured
from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
from django.db import connection
from django.http import HttpResponse, HttpResponseRedirect
from django.test.signals import setting_changed
from django.urls import resolve, reverse
Expand Down Expand Up @@ -1389,3 +1394,89 @@ def process_response(self, request, response):
header = self.option
response["Referrer-Policy"] = header
return response


class ProfilingMiddleware(BaseMiddleware):
"""
Adds the ability to profile requests via a header.
Usage:
Add the middleware to the MIDDLEWARE list. New boolean setting
"ENABLE_PROFILING" will be required to be set in the settings file. When
set to False, the middleware will deactivate itself. When set to True, the
middleware will be active.
When the middleware is active, it will log the data for any request that
supplies the X-Profile header in the HTTP request. This data will be logged
to the 'profiling' logger, so in order to see the results of this profiling
the Django logging will need to configure handlers for the 'profiling'
logger. Profiling will be configured at the DEBUG level.
"""

REQUIRED_SETTINGS = ("ENABLE_PROFILING", "DEBUG")
request_separator = f"\n{'=' * 80}\n"
query_separator = f"\n{'*' * 80}\n"

def __init__(self, get_response=None):
super().__init__(get_response)
if not self.enable_profiling:
raise MiddlewareNotUsed()

def load_setting(self, setting, value):
setattr(self, setting.lower(), value)

def format_queries_and_time_for_logs(self, queries):
formatted_queries = []
total_time = 0
for query in queries:
formatted_sql = sqlparse.format(
query["sql"], reindent=True, keyword_case="upper"
)

formatted_queries.append("{}:\n{}".format(query["time"], formatted_sql))
total_time += float(query["time"])

log_messages = [
f"\n{len(queries)} Queries\nTotal time for queries: {total_time}"
] + formatted_queries
return self.query_separator.join(log_messages)

def __call__(self, request):
# Only profile requests that have a 'X-Profile' HTTP header
if "HTTP_X_PROFILE" not in request.META:
return self.get_response(request)

out = StringIO()
out.write(self.request_separator)

# Add method & path info to differentiate requests
out.write(f"{request.method} {request.path}\n\n")

# We can only profile queries in debug mode
if self.debug:
num_previous_queries = len(connection.queries)

# Begin collecting time profiling data
profile = cProfile.Profile()
profile.enable()

# Continue down the middleware chain
response = self.get_response(request)

# Get the profile stats & pull out the top cumulative & total time
# data
profile_stats = pstats.Stats(profile, stream=out)
profile_stats = profile_stats.sort_stats("cumulative")
profile_stats.print_stats(128)
profile_stats.sort_stats("tottime")
profile_stats.print_stats(15)

# Print out our queries
if self.debug:
queries = connection.queries[num_previous_queries:]
out.write(self.format_queries_and_time_for_logs(queries))

out.write(self.request_separator)
logger.debug(out.getvalue())

return response

0 comments on commit 618f42e

Please sign in to comment.