Does SessionAuthentication work in Tastypie for HTTP POST?
Asked Answered
R

3

6

I am able to do GET to work with SessionAuthentication and Tastypie without setting any headers except for content-type to application/json. HTTP POST however just fails even though the Cookie in the Header has the session id. It fails with a 401 AuthorizationHeader but it has nothing to do with Authorization. Changing SessionAuthentication to BasicAuthentication and passing username/password works too.

Has anyone ever got SessionAuthentication to work with POST with Tastypie?

Rizika answered 13/3, 2013 at 14:53 Comment(0)
F
10

Yes I have gotten it to work. All you need to do is to pass the csfr token:

SessionAuthentication

This authentication scheme uses the built-in Django sessions to check if a user is logged. This is typically useful when used by Javascript on the same site as the API is hosted on.

It requires that the user has logged in & has an active session. They also must have a valid CSRF token.

This is how you do that in jQuery:

// sending a csrftoken with every ajax request
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    crossDomain: false, // obviates need for sameOrigin test
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
        }
    }
});

$.ajax({
    type: "POST",
    // ...

Notice the part that says $.cookie('csrftoken'). It gets the csrf token from a cookie that Django sets.

Update:

I had some problems with Django not setting the cookie on Firefox and Opera. Putting the template tag {% csrf_token %} in your template solves this. The right solution would probably be to use the decorator ensure_csrf_cookie().

Famagusta answered 13/3, 2013 at 17:53 Comment(3)
Also (and I found this using the Dev Http client plugin for chrome) the SessionAuthentication module does referer checking, so be sure you set the referer header as well.Shawn
use HTTP_X_CSRFTOKEN, X-CSRFToken workes for normal django request but not django tastypie POST or PUTArmes
Event after setting cookie, request.user is empty in angularjs $http({ 'method': "POST", 'url': "localhost:8000/isAuthenticated_user", headers:{ "X-CSRFToken": csrftoken, 'Content-Type': undefined // 'withCredentials':true }, })Mohamed
C
3

Here are some additions to Dan's answer. Please, correct me if something is wrong, I am still a bit confused about it myself.

Before we continue, read about CSRF protection in Django. Read it carefully. You need to put the token from the cookie into the header X-CSRFToken. This will not work if the cookie is Httponly, that is, if you have set CSRF-COOKIE-HTTPONLY = True in settings.py. Then you have to embed the cookie in the document which, of course, creates further vulnerabilities and reduces protection the gained by using Httponly.

As far as I can tell, if the cookie is not Httponly, jQuery sets X-CSRFToken automatically. Correct me if I am wrong, but I've just spent several hours playing with it, and this is what I am consistently getting. This makes me wonder, what is the point of the advice in Django documentation? Is it a new feature in jQuery?

Further discussion:

Tastypie disables CSRF protection except with Session Authentication, where it has custom code in authentication.py. You have to pass both the cookie csrftoken cookie and the header X-CSRFToken for the authentication to work. (This is Tastypie's requirement.) Assuming same domain, the browser will pass the cookies. JQuery will pass the header for you unless the csrftoken cookie is Httponly. Conversely, if the cookie is Httponly, I was unable to even manually set the header in $.ajaxSetup{beforeSend.... It appears that jQuery automatically sets X-CSRFToken to null if the csrftoken cookie is Httponly. At least I was able to set the header X-CS_RFToken to what I wanted, so I know I passed the value correctly. I am using jQuery 1.10.

If you are using curl for testing, you have to pass two cookies (sessionid and csrftoken), set the headers X-CSRFToken and, if the protocol is HTTPS, also set the Referrer.

Codie answered 23/4, 2014 at 0:1 Comment(0)
R
-1

I found this in the tastypie source code. Basically implies that HTTP POST is not supported by SessionAuthentication.

class SessionAuthentication(Authentication):
    """
    An authentication mechanism that piggy-backs on Django sessions.

    This is useful when the API is talking to Javascript on the same site.
    Relies on the user being logged in through the standard Django login
    setup.

    Requires a valid CSRF token.
    """
    def is_authenticated(self, request, **kwargs):
        """
        Checks to make sure the user is logged in & has a Django session.
        """
        # Cargo-culted from Django 1.3/1.4's ``django/middleware/csrf.py``.
        # We can't just use what's there, since the return values will be
        # wrong.
        # We also can't risk accessing ``request.POST``, which will break with
        # the serialized bodies.
        if request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            return request.user.is_authenticated()

So answering my own question here but if someone can explain it better and suggest a good way to do this, that would be great too.

Edit

I am currently using a workaround from https://github.com/amezcua/TastyPie-DjangoCookie-Auth/blob/master/DjangoCookieAuth.py which basically is a custom authentication scheme that fetches the session_id from the cookie and checks with the backend if it is authenticated. Might not be the most full proof solution but works great.

Rizika answered 13/3, 2013 at 16:25 Comment(1)
Small but important correction: this does not imply that POST is not supported by SessionAuthentication, it just means that additional checks (like CSRF) are going to happen for methods that modify data (POST, PUT, DELETE, etc.) Keep reading the rest of the method and see @dan-klasson's answer, which is correct...Jumpoff

© 2022 - 2024 — McMap. All rights reserved.