Ticket #14614: 14614.obfuscate-request-parameters.diff
File 14614.obfuscate-request-parameters.diff, 13.8 KB (added by , 13 years ago) |
---|
-
django/contrib/auth/views.py
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index cfb2659..ded6fe4 100644
a b from django.http import HttpResponseRedirect, QueryDict 6 6 from django.template.response import TemplateResponse 7 7 from django.utils.http import base36_to_int 8 8 from django.utils.translation import ugettext as _ 9 from django.views.decorators.logging import hide_parameters 9 10 from django.views.decorators.cache import never_cache 10 11 from django.views.decorators.csrf import csrf_protect 11 12 … … from django.contrib.auth.models import User 17 18 from django.contrib.auth.tokens import default_token_generator 18 19 from django.contrib.sites.models import get_current_site 19 20 20 21 @hide_parameters(POST=['password']) 21 22 @csrf_protect 22 23 @never_cache 23 24 def login(request, template_name='registration/login.html', … … def password_reset_done(request, 175 176 current_app=current_app) 176 177 177 178 # Doesn't need csrf_protect since no-one can guess the URL 179 @hide_parameters(POST=['new_password1', 'new_password2']) 178 180 @never_cache 179 181 def password_reset_confirm(request, uidb36=None, token=None, 180 182 template_name='registration/password_reset_confirm.html', … … def password_reset_complete(request, 227 229 return TemplateResponse(request, template_name, context, 228 230 current_app=current_app) 229 231 232 @hide_parameters(POST=['old_password', 'new_password1', 'new_password2']) 230 233 @csrf_protect 231 234 @login_required 232 235 def password_change(request, -
django/core/handlers/base.py
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index f216886..6ccf5b2 100644
a b class BaseHandler(object): 206 206 exc_info=exc_info, 207 207 extra={ 208 208 'status_code': 500, 209 'request': request209 'request': request 210 210 } 211 211 ) 212 212 -
django/core/handlers/modpython.py
diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index f0c7701..eb47a9f 100644
a b class ModPythonRequest(http.HttpRequest): 44 44 self._post_parse_error = False 45 45 self._stream = self._req 46 46 self._read_started = False 47 self.hidden_GET_parameters = [] 48 self.hidden_POST_parameters = [] 47 49 48 50 def __repr__(self): 49 51 # Since this is called as part of error handling, we need to be very -
django/core/handlers/wsgi.py
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 434f91c..54527ed 100644
a b class WSGIRequest(http.HttpRequest): 156 156 else: 157 157 self._stream = self.environ['wsgi.input'] 158 158 self._read_started = False 159 self.hidden_GET_parameters = [] 160 self.hidden_POST_parameters = [] 159 161 160 162 def __repr__(self): 161 163 # Since this is called as part of error handling, we need to be very 162 164 # robust against potentially malformed input. 163 165 try: 164 get = pformat(self. GET)166 get = pformat(self.safe_GET) 165 167 except: 166 168 get = '<could not parse>' 167 169 if self._post_parse_error: 168 170 post = '<could not parse>' 169 171 else: 170 172 try: 171 post = pformat(self. POST)173 post = pformat(self.safe_POST) 172 174 except: 173 175 post = '<could not parse>' 174 176 try: … … class WSGIRequest(http.HttpRequest): 176 178 except: 177 179 cookies = '<could not parse>' 178 180 try: 179 meta = pformat(self. META)181 meta = pformat(self.safe_META) 180 182 except: 181 183 meta = '<could not parse>' 182 184 return '<WSGIRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ -
django/http/__init__.py
diff --git a/django/http/__init__.py b/django/http/__init__.py index 0d28ec0..5fc7bb6 100644
a b class HttpRequest(object): 144 144 self.path = '' 145 145 self.path_info = '' 146 146 self.method = None 147 self.hidden_GET_parameters = [] 148 self.hidden_POST_parameters = [] 147 149 148 150 def __repr__(self): 149 151 return '<HttpRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ 150 (pformat(self.GET), pformat(self.POST), pformat(self.COOKIES), 151 pformat(self.META)) 152 152 (pformat(self.safe_GET), 153 pformat(self.safe_POST), 154 pformat(self.COOKIES), 155 pformat(self.safe_META)) 156 157 @property 158 def safe_GET(self): 159 if settings.DEBUG: 160 return self.GET 161 result = self.GET.copy() 162 for param in self.hidden_GET_parameters: 163 if result.has_key(param): 164 result[param] = u'********************' 165 return result 166 167 @property 168 def safe_POST(self): 169 if settings.DEBUG: 170 return self.POST 171 result = self.POST.copy() 172 for param in self.hidden_POST_parameters: 173 if result.has_key(param): 174 result[param] = u'********************' 175 return result 176 177 @property 178 def safe_META(self): 179 if settings.DEBUG: 180 return self.META 181 result = self.META.copy() 182 result['QUERY_STRING'] = self.safe_GET.urlencode(safe='*') 183 return result 184 153 185 def get_host(self): 154 186 """Returns the HTTP host using the environment or request headers.""" 155 187 # We try three options, in order of decreasing preference. -
django/views/debug.py
diff --git a/django/views/debug.py b/django/views/debug.py index 67f25b3..be81988 100644
a b import os 3 3 import re 4 4 import sys 5 5 import types 6 import functools 6 7 7 8 from django.conf import settings 8 9 from django.http import HttpResponse, HttpResponseServerError, HttpResponseNotFound … … from django.template.defaultfilters import force_escape, pprint 12 13 from django.utils.html import escape 13 14 from django.utils.importlib import import_module 14 15 from django.utils.encoding import smart_unicode, smart_str 16 from django.core.exceptions import ImproperlyConfigured 15 17 16 18 HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST|SIGNATURE') 17 19 … … TECHNICAL_500_TEMPLATE = """ 425 427 {% if request %} 426 428 <tr> 427 429 <th>Request Method:</th> 428 <td>{{ request. META.REQUEST_METHOD }}</td>430 <td>{{ request.safe_META.REQUEST_METHOD }}</td> 429 431 </tr> 430 432 <tr> 431 433 <th>Request URL:</th> … … Exception Value: {{ exception_value|force_escape }} 621 623 622 624 {% if request %} 623 625 <h3 id="get-info">GET</h3> 624 {% if request. GET %}626 {% if request.safe_GET %} 625 627 <table class="req"> 626 628 <thead> 627 629 <tr> … … Exception Value: {{ exception_value|force_escape }} 630 632 </tr> 631 633 </thead> 632 634 <tbody> 633 {% for var in request. GET.items %}635 {% for var in request.safe_GET.items %} 634 636 <tr> 635 637 <td>{{ var.0 }}</td> 636 638 <td class="code"><pre>{{ var.1|pprint }}</pre></td> … … Exception Value: {{ exception_value|force_escape }} 643 645 {% endif %} 644 646 645 647 <h3 id="post-info">POST</h3> 646 {% if request. POST %}648 {% if request.safe_POST %} 647 649 <table class="req"> 648 650 <thead> 649 651 <tr> … … Exception Value: {{ exception_value|force_escape }} 652 654 </tr> 653 655 </thead> 654 656 <tbody> 655 {% for var in request. POST.items %}657 {% for var in request.safe_POST.items %} 656 658 <tr> 657 659 <td>{{ var.0 }}</td> 658 660 <td class="code"><pre>{{ var.1|pprint }}</pre></td> … … Exception Value: {{ exception_value|force_escape }} 717 719 </tr> 718 720 </thead> 719 721 <tbody> 720 {% for var in request. META.items|dictsort:"0" %}722 {% for var in request.safe_META.items|dictsort:"0" %} 721 723 <tr> 722 724 <td>{{ var.0 }}</td> 723 725 <td class="code"><pre>{{ var.1|pprint }}</pre></td> -
new file django/views/decorators/logging.py
diff --git a/django/views/decorators/logging.py b/django/views/decorators/logging.py new file mode 100644 index 0000000..d696042
- + 1 import functools 2 from django.core.exceptions import ImproperlyConfigured 3 4 def hide_parameters(GET=None, POST=None, all=None): 5 if callable(GET) and POST is None and all is None: 6 # The decorator is called directly on the view without `GET`, `POST` or `all` argument. 7 view = GET 8 raise ImproperlyConfigured('hide_parameters requires at least one value for `GET`, `POST` or `all` for `%s`.' % view.__name__) 9 GET = list(GET) if GET else [] 10 POST = list(POST) if POST else [] 11 all = list(all) if all else [] 12 def decorator(view): 13 @functools.wraps(view) 14 def wrapper(request, *args, **kwargs): 15 request.hidden_GET_parameters = GET + all 16 request.hidden_POST_parameters = POST + all 17 return view(request, *args, **kwargs) 18 return wrapper 19 return decorator -
tests/regressiontests/views/tests/debug.py
diff --git a/tests/regressiontests/views/tests/debug.py b/tests/regressiontests/views/tests/debug.py index d778311..d98bdd3 100644
a b 1 from __future__ import with_statement 1 2 import inspect 2 3 import sys 3 4 4 5 from django.conf import settings 6 from django.core.exceptions import ImproperlyConfigured 5 7 from django.core.files.uploadedfile import SimpleUploadedFile 6 8 from django.test import TestCase, RequestFactory 7 9 from django.core.urlresolvers import reverse 8 10 from django.template import TemplateSyntaxError 9 11 from django.views.debug import ExceptionReporter 12 from django.views.decorators.logging import hide_parameters 10 13 11 14 from regressiontests.views import BrokenException, except_args 15 from regressiontests.views.views import hidden_params 12 16 13 17 14 18 class DebugViewTests(TestCase): … … class ExceptionReporterTests(TestCase): 81 85 self.assertIn('<h2>Request information</h2>', html) 82 86 self.assertNotIn('<p>Request data not supplied</p>', html) 83 87 88 def test_hidden_parameters(self): 89 with self.assertRaises(ImproperlyConfigured) as context_manager: 90 hide_parameters(hidden_params) 91 self.assertEqual(context_manager.exception.message, 'hide_parameters requires at least one value for `GET`, `POST` or `all` for `hidden_params`.') 92 93 data = {'sausage-key': 'sausage-value', 94 'baked-beans-key': 'baked-beans-value', 95 'hash-brown-key': 'hash-brown-value', 96 'eggs-key': 'eggs-value', 97 'bacon-key': 'bacon-value',} 98 99 with self.settings(DEBUG=False): 100 # Using GET 101 request = self.rf.get('/hidden_params/', data) 102 response = hidden_params(request) 103 request_repr = repr(request) 104 for k, v in data.items(): 105 # All parameters' names can be seen. 106 self.assertTrue(k in request_repr) 107 # Only some parameters' values can be seen 108 self.assertTrue('sausage-value' in request_repr) 109 self.assertTrue('baked-beans-value' in request_repr) 110 self.assertTrue('hash-brown-value' in request_repr) 111 self.assertTrue('eggs-value' not in request_repr) 112 self.assertTrue('bacon-value' not in request_repr) 113 114 # Using POST 115 request = self.rf.post('/hidden_params/', data) 116 response = hidden_params(request) 117 request_repr = repr(request) 118 for k, v in data.items(): 119 # All parameters' names can be seen. 120 self.assertTrue(k in request_repr) 121 # Only some parameters' values can be seen. 122 self.assertTrue('sausage-value' in request_repr) 123 self.assertTrue('baked-beans-value' not in request_repr) 124 self.assertTrue('hash-brown-value' not in request_repr) 125 self.assertTrue('eggs-value' in request_repr) 126 self.assertTrue('bacon-value' not in request_repr) 127 128 with self.settings(DEBUG=True): 129 # Everything can be seen in DEBUG mode. 130 131 # Using GET 132 request = self.rf.get('/hidden_params/', data) 133 response = hidden_params(request) 134 request_repr = repr(request) 135 for k, v in data.items(): 136 self.assertTrue(k in request_repr) 137 self.assertTrue(v in request_repr) 138 139 # Using POST 140 request = self.rf.post('/hidden_params/', data) 141 response = hidden_params(request) 142 request_repr = repr(request) 143 for k, v in data.items(): 144 self.assertTrue(k in request_repr) 145 self.assertTrue(v in request_repr) 146 84 147 def test_no_request(self): 85 148 "An exception report can be generated without request" 86 149 try: -
tests/regressiontests/views/views.py
diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py index 11d289f..aea7b7b 100644
a b from django.core.urlresolvers import get_resolver 6 6 from django.shortcuts import render_to_response, render 7 7 from django.template import Context, RequestContext, TemplateDoesNotExist 8 8 from django.views.debug import technical_500_response 9 from django.views.decorators.logging import hide_parameters 9 10 10 11 from regressiontests.views import BrokenException, except_args 11 12 … … def raises_template_does_not_exist(request): 128 129 return render_to_response('i_dont_exist.html') 129 130 except TemplateDoesNotExist: 130 131 return technical_500_response(request, *sys.exc_info()) 132 133 @hide_parameters(POST=('hash-brown-key', 'baked-beans-key'), GET=('eggs-key',), all=('bacon-key',)) 134 def hidden_params(request): 135 return HttpResponse('')