views:

884

answers:

3

Hello,

I want to be sure that for some URL of my website, SSL will be use. I saw a lot of answer already on SO.

http://stackoverflow.com/questions/724968/force-redirect-to-ssl-for-all-pages-apart-from-one

So I think I will use mod_rewrite.

My question is more about how to configure the Virtual Host to run my Django Application over HTTP and over HTTPS without problems. I am using WSGI.

Is it a problem to just duplicate the configuration over *:443 and over *:80 ? How should I do to have the best configuration ?

Thank you.

Rémy

+4  A: 

Besides using mod_rewrite, you can also use Django to control the SSL redirects.

Here's a modified version of a middleware from the Satchmo Project. I tend to like this method better than mod_rewrite as it's easier to manage.

To use it, pass 'SSL':True into your url conf:


    urlpatterns = patterns('some_site.some_app.views',
        (r'^test/secure/$','test_secure',{'SSL':True}),
    )

Here's the middleware code:


    from django.conf import settings
    from django.http import HttpResponseRedirect, get_host

    SSL = 'SSL'

    def request_is_secure(request):
        if request.is_secure():
            return True

        # Handle forwarded SSL (used at Webfaction)
        if 'HTTP_X_FORWARDED_SSL' in request.META:
            return request.META['HTTP_X_FORWARDED_SSL'] == 'on'

        if 'HTTP_X_SSL_REQUEST' in request.META:
            return request.META['HTTP_X_SSL_REQUEST'] == '1'

        return False

    class SSLRedirect:
        def process_request(self, request):
            if request_is_secure(request):
                request.IS_SECURE=True
            return None

        def process_view(self, request, view_func, view_args, view_kwargs):          
            if SSL in view_kwargs:
                secure = view_kwargs[SSL]
                del view_kwargs[SSL]
            else:
                secure = False

            if settings.DEBUG:
                return None

            if getattr(settings, "TESTMODE", False):
                return None

            if not secure == request_is_secure(request):
                return self._redirect(request, secure)

        def _redirect(self, request, secure):
            if settings.DEBUG and request.method == 'POST':
                raise RuntimeError(
                """Django can't perform a SSL redirect while maintaining POST data.
                    Please structure your views so that redirects only occur during GETs.""")

            protocol = secure and "https" or "http"

            newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())


Chip Tol
This is useful too. To be sure that it is a SSL connexion. Do you think it is better to handle it with django. Or with Mod_Rewrite ?
Natim
Like I mentioned, I tend to like managing it in Django, as it's easier to see what URLs are secured via SSL. If you need to secure a URL, just update the urls.py file, and you're done. No messy (well, messier) mod_rewrite rules needed.
Chip Tol
A: 

We used some simple middleware to check urls against a list of base urls that must be in HTTPS mode, all others are forced to HTTP mode. The big caveat here is that any POST data can be lost unless you take extra care (it didn't matter in our case). We were doing this on join pages that required credit card numbers and the like so as soon as they were in that pipeline we forced them into HTTPS.

Peter Rowell
+1  A: 

If by WSGI you actually mean Apache/mod_wsgi, then although mounted WSGI applications normally get run in their own sub interpreters, the 80/443 split is a special case and even though in different VirtualHost so long as mount point for WSGIScriptAlias, and the ServerName are the same, they will be merged.

<VirtualHost *:80>
ServerName www.example.com

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

<VirtualHost *:443>
ServerName www.example.com

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

This will happen for daemon mode as well, but with daemon mode you need to define only a single daemon process group in first VirtualHost definition and then just refer to that from both with WSGIProcessGroup.

<VirtualHost *:80>
ServerName www.example.com

WSGIDaemonProcess mydjangosite ...
WSGIProcessGroup mydjangosite

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

<VirtualHost *:444>
ServerName www.example.com

WSGIProcessGroup mydjangosite

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

The WSGIProcessGroup can only reach across like to that VirtualHost for same ServerName.

Django provides a is_secure() method for determining when request came via HTTPS which derives from WSGI variable with request called 'wsgi.url_scheme' which is set by mod_wsgi.

So, you would have one single Django WSGI script file and settings file. You just need to duplicate application mounting as decsribed in Apache/mod_wsgi configuration.

Graham Dumpleton
Ok thank you. It is exactly what I was looking for.
Natim