Ticket #5515: 5515_make_403_errors_customizable.diff

File 5515_make_403_errors_customizable.diff, 8.8 KB (added by progprog, 13 years ago)

Patch to make 403 responses work like 404 and 500 responses (customizable via handler)

  • django/conf/urls/defaults.py

     
    11from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
    22from django.core.exceptions import ImproperlyConfigured
    33
    4 __all__ = ['handler404', 'handler500', 'include', 'patterns', 'url']
     4__all__ = ['handler403', 'handler404', 'handler500', 'include', 'patterns', 'url']
    55
     6handler403 = 'django.views.defaults.permission_denied'
    67handler404 = 'django.views.defaults.page_not_found'
    78handler500 = 'django.views.defaults.server_error'
    89
  • django/core/urlresolvers.py

     
    268268        except (ImportError, AttributeError), e:
    269269            raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e))
    270270
     271    def resolve403(self):
     272        return self._resolve_special('403')
     273
    271274    def resolve404(self):
    272275        return self._resolve_special('404')
    273276
  • django/core/handlers/base.py

     
    105105            else:
    106106                callback, param_dict = resolver.resolve404()
    107107                return callback(request, **param_dict)
    108         except exceptions.PermissionDenied:
    109             return http.HttpResponseForbidden('<h1>Permission denied</h1>')
     108        except exceptions.PermissionDenied, e:
     109            callback, param_dict = resolver.resolve403()
     110            param_dict['reason'] = e.message
     111            return callback(request, **param_dict)
    110112        except SystemExit:
    111113            pass # See http://code.djangoproject.com/ticket/1023
    112114        except: # Handle everything else, including SuspiciousOperation, etc.
  • django/core/exceptions.py

     
    1010
    1111class PermissionDenied(Exception):
    1212    "The user did not have permission to do that"
    13     pass
     13    def __init__(self, message=None):
     14        Exception.__init__(self)
     15        self.message = message
    1416
    1517class ViewDoesNotExist(Exception):
    1618    "The requested view does not exist"
  • django/views/defaults.py

     
    6666    else:
    6767        return http.HttpResponseRedirect(absurl)
    6868
     69def permission_denied(request, template_name='403.html', reason=''):
     70    """
     71    Default 403 handler.
     72
     73    Templates: `403.html`
     74    Context:
     75        request_path
     76            The path of the requested URL (e.g., '/app/pages/form_page')   
     77    """
     78    context = {
     79        'request_path': request.path,
     80        'reason': reason,
     81    }
     82    t = loader.get_template(template_name) # You need to create a 403.html template.
     83    return http.HttpResponseForbidden(t.render(RequestContext(request, context)))
     84
    6985def page_not_found(request, template_name='404.html'):
    7086    """
    7187    Default 404 handler, which looks for the requested URL in the redirects
  • django/contrib/csrf/middleware.py

     
    66
    77"""
    88from django.conf import settings
     9from django.core.exceptions import PermissionDenied
    910from django.http import HttpResponseForbidden
    1011from django.utils.safestring import mark_safe
    1112import md5
    1213import re
    1314import itertools
    1415
    15 _ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
     16_ERROR_MSG = "Cross Site Request Forgery detected."
    1617
    1718_POST_FORM_RE = \
    1819    re.compile(r'(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
     
    5354            try:
    5455                request_csrf_token = request.POST['csrfmiddlewaretoken']
    5556            except KeyError:
    56                 return HttpResponseForbidden(_ERROR_MSG)
     57                raise PermissionDenied(_ERROR_MSG)
    5758           
    5859            if request_csrf_token != csrf_token:
    59                 return HttpResponseForbidden(_ERROR_MSG)
     60                raise PermissionDenied(_ERROR_MSG)
    6061               
    6162        return None
    6263
  • django/contrib/csrf/tests.py

     
     1r"""
     2>>> from django.conf import settings
     3>>> from django import http
     4>>> from django.contrib.csrf.middleware import CsrfMiddleware, _make_token
     5>>> csrf = CsrfMiddleware()
     6>>> request = http.HttpRequest()
     7>>> request.method = 'POST'
     8
     9If no session exists, returns None (check not required)
     10>>> csrf.process_request(request)
     11
     12If token doesn't exist, raise PermissionDenied
     13>>> request.COOKIES[settings.SESSION_COOKIE_NAME] = 'my_session_id'
     14>>> csrf.process_request(request)
     15Traceback (most recent call last):
     16    ...
     17PermissionDenied
     18
     19If token exists and does not match session id, raise PermissionDenied
     20>>> request.POST['csrfmiddlewaretoken'] = 'hackers_session_id'
     21>>> csrf.process_request(request)
     22Traceback (most recent call last):
     23    ...
     24PermissionDenied
     25
     26>>> request.POST['csrfmiddlewaretoken'] = _make_token('my_session_id')
     27>>> csrf.process_request(request)
     28
     29"""
     30
     31if __name__ == '__main__':
     32    import doctest
     33    doctest.testmod()
  • tests/regressiontests/views/tests/defaults.py

     
    2525            response = self.client.get(short_url)
    2626            self.assertEquals(response.status_code, 404)
    2727
     28    def test_permission_denied(self):
     29        "A 403 status is returned by the permission_denied view"
     30        response = self.client.get('/views/permission_denied_url/')
     31        self.assertEquals(response.status_code, 403)
     32
     33    def test_permission_denied_with_reason(self):
     34        "A 403 status can propagate the reason for denying to the permission_denied view"
     35        response = self.client.get('/views/permission_denied_with_reason/')
     36        self.assertContains(response, "Not allowed", status_code=403)
     37
    2838    def test_page_not_found(self):
    2939        "A 404 status is returned by the page_not_found view"
    3040        non_existing_urls = ['/views/non_existing_url/', # this is in urls.py
     
    3444            self.assertEquals(response.status_code, 404)
    3545
    3646    def test_server_error(self):
    37         "The server_error view raises a 500 status"
     47        "A 500 status is returned by the server_error view"
    3848        response = self.client.get('/views/server_error/')
    3949        self.assertEquals(response.status_code, 500)
  • tests/regressiontests/views/views.py

     
     1from django.core.exceptions import PermissionDenied
    12from django.http import HttpResponse
    23from django.template import RequestContext
    34
     
    56    """Dummy index page"""
    67    return HttpResponse('<html><body>Dummy page</body></html>')
    78
     9def generate_permission_denied_with_reason(request):
     10    """Dummy page to test Permission Denied exception with reason"""
     11    raise PermissionDenied("Not allowed")
  • tests/regressiontests/views/urls.py

     
    2525   
    2626    # Default views
    2727    (r'^shortcut/(\d+)/(.*)/$', 'django.views.defaults.shortcut'),
     28    (r'^permission_denied_url/', 'django.views.defaults.permission_denied'),
     29    (r'^permission_denied_with_reason/', views.generate_permission_denied_with_reason),
    2830    (r'^non_existing_url/', 'django.views.defaults.page_not_found'),
    2931    (r'^server_error/', 'django.views.defaults.server_error'),
    3032   
  • tests/templates/403.html

     
     1Django Internal Tests: 403 Error
     2{{ reason }}
Back to Top