I'm using a combination of flask-jwt-extended for JWT authentication, and I've enabled CSRF protection, meaning for certain HTTP methods (PUT, POST, DELETE...), it is required that the value in the cookie and the HTTP header match.
This works fine for my API requests, where I just construct the HTTP request in JS with the header set correctly, but I want to use Flask-Admin, and allow access based on the JWT tokens. I did this by decorating the is_accessible function in Flask-Admin's ModelView with #jwt_optional and checking within it.
However, now when I try to perform any modifications through Flask-Admin, I get an error message from flask-jwt-extended, stating that I didn't properly include my CSRF tokens. This is true, as I'm using the default forms that come with Flask-Admin.
My question is, what is the best solution? Is it possible to disable CSRF protection only for certain paths? (And enable Flask-Admin's own CSRF protection for them?) Should I modify the views and insert JS that is triggered by the submit button but actually submits an XmlHTTPRequest? Should I implement the JWT authentication for Flask-Admin views in a different way?
Related
I'm trying to use Python to authenticate to https://anchor.fm/login.
The problem is that the payload requires a _csrf property.
So I don't think it's possible to use a simple POST method.
So, I would like to know if it is possible to get the attributes of the form (id="LoginForm") to do the authentication:
If yes, is there any package that helps me to do this? Or some other method.
The login page makes a GET request to https://anchor.fm/api/csrf to get a csrf token. This request also sets a cookie, which is then sent together with the login form. I haven't checked that, but it seems it should be enough to make that GET request, grab the csrf token and the cookie, and attach them to the POST you make with the login form. (the csrf token in the _csrf body field, as you noted)
I apologize in advance for asking a rather cryptic question. However, I did not understand it despite going through a lot of material. It would be great if you could shed some light on this.
What is the purpose of a request_loader in flask-login? How does it interact with the user_loader decorator?
If I am using a token based authentication system (I am planning on sending the token to my angularJS front end, storing the token there and sending that token in the authorization-token header), will I need a request_loader or will a user_loader (where I check the auth header and see if the user exists) suffice?
From the Flask-Login documentation:
Sometimes you want to login users without using cookies, such as using
header values or an api key passed as a query argument. In these cases,
you should use the request_loader callback. This callback should
behave the same as your user_loader callback, except that it accepts
the Flask request instead of a user_id.
So, to answer your question, they both serve the same function for Flask-Login. They are both used to load the user. request_loader, however, is appropriate for custom logins.
Here's a great tutorial I found that utilizes request_loader to take advantage of token based authentication (The post is not my own, I'm merely sharing the link): http://gouthamanbalaraman.com/blog/minimal-flask-login-example.html
I need to make this clear.
This is the reason why you shoud use request_loader with flask_login.
There will be a lot of #login_required from flask_login used in your api to guard the request access.
You need to make a request to pass the check of auth.
And there will be a lot of current_user imported from flask_login,
Your app need to use them to let the request act as the identity of the current_user.
There are two ways to achieve the above with flask_login.
Using user_loader makes the request to be OK for #login_required.
It is often used for UI logins from browser.
It will store session cookies to the browser and use them to auth later.
So you need to login only once and the session will keep for a time.
Using request_loader will also be OK with #login_required.
But it is often used with api_key or basic auth.
For example used by other apps to interact with your flask app.
There will be no session cookies,
so you need to provide the auth info every time you send request.
With both user_loader and request_loader,
now you got 2 ways of auth for the same api,
protected by #login_required,
and with current_user usable,
which is really smart.
To verify users with Flask-Login's session_id for frontend requests through Angular, you must set the withCredentials configuration flag to true.
That is, if you are using Angular's $http.post(url,data [,config]) or $http.get(url [,config]), make sure the config object contains the property withCredentials set to true. This will instruct the browser to use its cookies in the same way it would for a full-on page visit.
For example,
$http.post('/api/login',{username:'myusername',password:'mypassword'},{withCredentials:true})
will post the data {username:'myusername',password:'mypassword'} to your site/app's /api/login route and, if you're using Flask-Login and are logged in, Flask will know.
You can set this behavior for all $http service requests by setting
$httpProvider.defaults.withCredentials=true
somewhere in your app. Currently, I have that line of code in my app.config block, which seems appropriate to me:
var myApp = angular.module('myApp');
myApp.config(function ($httpProvider) {
$httpProvider.defaults.withCredentials = true;
});
(Since this post is about Flask, folks may want to send form data through Angular in such a way that it can be found in request.form, which has a similar solution, fyi.)
I want to use both token and session based authentication in my application with the priority of token. I have created two portal with the same URL one is using session and other is using token. So when session is available in cookie then token based request goes failed with "CSRF Token is missing" error message.
One solution I have in my mind using middle-ware where I can make priority to token. If both are available in request then custom middle-ware will remove session related stuffs and keep only token related information and proceed.
If anyone has solution available for this problem then please post in answer?
Thanks in advance.
In my case I have written custom middle-ware to handle the situation.
1. When I am login using API and api path is **/api/accounts/login**. So when request comes on this url then I am removing sessionid and csrftoken both.
When HTTP_AUTHORIZATION is available in request, I remove the session and csrftoken.
Using above two removal situation can be handled in my case.
Thanks to everyone for helping.!!
Django middleware execute in order according to the MIDDLEWARE_CLASSES tuple.
You'll want to ensure your Token based authentication middleware is located after AuthenticationMiddleware in MIDDLEWARE_CLASSES.
The docs describe this approach in the context of RemoteUserMiddleware.
I am using Django framework for my backend support for a mobile app.
I choose to use the original Django's views.py to get my API url mapping and dump JSON for response, rather than using other REST frameworks like Django REST Framwork or TastiPie.
Now if I make a cross domain HTTP Request from my mobile client app. normally I will get a 403 Forbidden error because of Django's built-in CSRF protection. It seems like it can only work when I exempt it explicitly before each function in views.py. My question is, is it safe to exempt the protection? If exempt csrf is not a good way to do, what suggestions do you have on my situation?
Thanks
I have the solution, this is more of a Why question. The problem is when running a django dev server, when i make an ajax POST request with data, if the view never looks at the POST dict, i get a urllib2 exception. "a connection was forcibly closed by a remote host" or something.
If theres no post data, it returns fine, if the data is read, not even stored, a simple
request.POST
will return ok as well. Why is this?
Thanks
I'm guessing you're not sending the csrfmiddleware_token on your post request. It's a prevention mechanism for CSRF attacks and needs to be set on all POST messages. See the documentation for details.
You need to disable CSRF protection for that view function as it is enabled by default (the CSRF Middleware).
You can opt to disable CSRF protection via two ways:
Remove the CSRF middleware and use the #csrf_protect decorator on
view functions that you wish to use the CSRF protection. Use this if you generally don't
need CSRF (eg. no forms for most of the pages). See https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#the-decorator-method
Use the #csrf_exempt decorator on the view you wish to exempt the CSRF protection from.
This is useful when you only have a few view functions that does not require CSRF
protection. See https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#exceptions