3 Mar 2014

CSRF verification failed while making POST request from REST client

Problem :  CSRF verification failed
Recently i was using the chrome REST extension for testing the API calls.

When a POST request is made for a django url using extension, i got 403 forbidden error with message

CSRF verification failed. Request aborted

Why this problem?
I dig to the django docs and found that with every POST request a CSRF token is required.
So it was needed to pass that CSRF token as a value of X-CSRFToken Http header as a part of POST request.

Solution
find the the value of CSRF token and pass it as a value X-CSRFToken header in POST request.
Pretty easy to find CSRF token value by using request object.
 >> request.COOKIES['csrftoken']
'ofDXgUB8kChf7pRkUypjDdtGrQsK8xYb'
or
 >> request.META['CSRF_COOKIE']
'ofDXgUB8kChf7pRkUypjDdtGrQsK8xYb'


1 Mar 2014

Source code : django.http.request

Learning from source code is a best way to grasp the concepts behind  a framework, library or a language.
So I got the copy Django source code and started with module django.http.request module. In this post i'm going to share what i have learned from that.

1.  DEBUG and ALLOWED_HOSTS
When DEBUG is False make sure you have initialized the ALLOWED_HOSTS, otherwise get the SuspiciousOperation error.

A host is either HTTP_HOST or HTTP_X_FORWARDED_HOST. If  DEBUG is True that host is used and if DEBUG is False then host is validated from ALLOWED_HOSTS list.
        # There is no hostname validation when DEBUG=True
        if settings.DEBUG:
            return host

        domain, port = split_domain_port(host)
        if domain and validate_host(domain, settings.ALLOWED_HOSTS):
            return host
        else:
            msg = "Invalid HTTP_HOST header: %r." % host
            if domain:
                msg += "You may need to add %r to ALLOWED_HOSTS." % domain
            else:
                msg += "The domain name provided is not valid according to RFC 1034/1035"
            raise DisallowedHost(msg)


When that host name is not found in ALLOWED_HOSTS it throws error :
SuspiciousOperation: Invalid HTTP_HOST header (you may need to set ALLOWED_HOSTS): localhost:8000
Solution is to add a hostname string in ALLOWED_HOSTS list.


2. Finding request scheme (i.e. http or https)
Inelegant attempt is to check the request.META for 'wsgi.url_scheme'.
 >> request.META[''wsgi.url_scheme']
'http'

Ideally 'scheme' attribute should be related to the request object, something like request.scheme
Up-to the Django version 1.6 there is no 'scheme' attribute for request object.
At this point i was a bit excited to suggest a django ticket for that.
But i found that in development version they are going to associate scheme to request object.


So these two stuff i found , hope to share more in coming posts.