| 1 |
""" |
|---|
| 2 |
SSL Middleware |
|---|
| 3 |
Stephen Zabel |
|---|
| 4 |
|
|---|
| 5 |
This middleware answers the problem of redirecting to (and from) a SSL secured path |
|---|
| 6 |
by stating what paths should be secured in urls.py file. To secure a path, add the |
|---|
| 7 |
additional view_kwarg 'SSL':True to the view_kwargs. |
|---|
| 8 |
|
|---|
| 9 |
For example |
|---|
| 10 |
|
|---|
| 11 |
urlpatterns = patterns('some_site.some_app.views', |
|---|
| 12 |
(r'^test/secure/$','test_secure',{'SSL':True}), |
|---|
| 13 |
) |
|---|
| 14 |
|
|---|
| 15 |
All paths where 'SSL':False or where the kwarg of 'SSL' is not specified are routed |
|---|
| 16 |
to an unsecure path. |
|---|
| 17 |
|
|---|
| 18 |
For example |
|---|
| 19 |
|
|---|
| 20 |
urlpatterns = patterns('some_site.some_app.views', |
|---|
| 21 |
(r'^test/unsecure1/$','test_unsecure',{'SSL':False}), |
|---|
| 22 |
(r'^test/unsecure2/$','test_unsecure'), |
|---|
| 23 |
) |
|---|
| 24 |
|
|---|
| 25 |
Gotcha's : Redirects should only occur during GETs; this is due to the fact that |
|---|
| 26 |
POST data will get lost in the redirect. |
|---|
| 27 |
|
|---|
| 28 |
A major benefit of this approach is that it allows you to secure django.contrib views |
|---|
| 29 |
and generic views without having to modify the base code or wrapping the view. |
|---|
| 30 |
|
|---|
| 31 |
This method is also better than the two alternative approaches of adding to the |
|---|
| 32 |
settings file or using a decorator. |
|---|
| 33 |
|
|---|
| 34 |
It is better than the tactic of creating a list of paths to secure in the settings |
|---|
| 35 |
file, because you DRY. You are also not forced to consider all paths in a single |
|---|
| 36 |
location. Instead you can address the security of a path in the urls file that it |
|---|
| 37 |
is resolved in. |
|---|
| 38 |
|
|---|
| 39 |
It is better than the tactic of using a @secure or @unsecure decorator, because |
|---|
| 40 |
it prevents decorator build up on your view methods. Having a bunch of decorators |
|---|
| 41 |
makes views cumbersome to read and looks pretty redundant. Also because the all |
|---|
| 42 |
views pass through the middleware you can specify the only secure paths and the |
|---|
| 43 |
remaining paths can be assumed to be unsecure and handled by the middleware. |
|---|
| 44 |
|
|---|
| 45 |
This package is inspired by Antonio Cavedoni's SSL Middleware |
|---|
| 46 |
""" |
|---|
| 47 |
|
|---|
| 48 |
__license__ = "Python" |
|---|
| 49 |
__copyright__ = "Copyright (C) 2007, Stephen Zabel" |
|---|
| 50 |
__author__ = "Stephen Zabel" |
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 |
from django.conf import settings |
|---|
| 54 |
from django.http import HttpResponseRedirect, get_host |
|---|
| 55 |
|
|---|
| 56 |
SSL = 'SSL' |
|---|
| 57 |
|
|---|
| 58 |
class SSLRedirect: |
|---|
| 59 |
def process_view(self, request, view_func, view_args, view_kwargs): |
|---|
| 60 |
if SSL in view_kwargs: |
|---|
| 61 |
secure = view_kwargs[SSL] |
|---|
| 62 |
del view_kwargs[SSL] |
|---|
| 63 |
else: |
|---|
| 64 |
secure = False |
|---|
| 65 |
|
|---|
| 66 |
if not secure == request.is_secure(): |
|---|
| 67 |
return self._redirect(request, secure) |
|---|
| 68 |
|
|---|
| 69 |
def _redirect(self, request, secure): |
|---|
| 70 |
protocol = secure and "https" or "http" |
|---|
| 71 |
newurl = "%s://%s%s" % (protocol, |
|---|
| 72 |
get_host(request), |
|---|
| 73 |
request.get_full_path()) |
|---|
| 74 |
|
|---|
| 75 |
if settings.DEBUG and request.method == 'POST': |
|---|
| 76 |
raise RuntimeError, \ |
|---|
| 77 |
"""Django can't perform a SSL redirect while maintaining POST data. |
|---|
| 78 |
Please structure your views so that redirects only occur during GETs.""" |
|---|
| 79 |
|
|---|
| 80 |
return HttpResponseRedirect(newurl) |
|---|