In a web application already using django.contrib.auth for authentication, I'm looking for the "standard" approach for restricting access to Ajax services to authenticated users only.
Using the #login_required decorator won't do, because that just redirects unauthenticated users to a login page. For a service, we should probably be sending a valid, well-formed error response back -- not some login form.
This is the first approach that comes to mind:
from django.http import HttpResponse
def some_json_service_view(request):
if not request.user.is_authenticated():
return HttpResponse('{success: false}')
return HttpResponse('{success: true}')
Taking it one step farther, if I could standardize on a single response for all "not authenticated" errors, then a decorator would be nice:
from django.http import HttpResponse
def login_required_json(f):
def new_f(request):
if not request.user.is_authenticated():
return HttpResponse('{success: false}')
return f(request)
return new_f
#login_required_json
def some_json_service_view(request):
return HttpResponse('{success: true}')
Is this how everybody else does it, or is there a more accepted way it's done? Ideally, someone could point me to the django.contrib package made for this purpose.
That's an example that will work great if the AJAX services are consumed by your front-end clients only. I do that all the time, because the same design gets used for pushing all other kinds of data to the client through the response for which the client needs to perform additional actions or otherwise provide some feedback to the user. It works great when your site has mixed users, i.e. you support both anonymous and registered users.
If your building services for 3rd party vendors though, you'll either have to use OAuth, basic HTTP access authentication or digest HTTP access authentication. You do this when you know/assume that users who are performing the requests all have registered credentials. Hence, these authentication schemes allow a user to authenticate themselves if the authentication system challenges them for credentials, which they can immediately supply at hand, without manually having to enter them at a redirected login page.
So if your services have mixed users, I'd stick with what you have. Otherwise, you'll have to take up on something more elaborate, something that assumes that unauthenticated users have and can immediately supply their credentials.
In either case, I suggest you take a look at django-piston. It's like a pretty straightforward controller for parsing AJAX requests and serializing AJAX responses. Based on the supplied model and HTTP verb, it can automatically do a lot of the heavy lifting for you when exposing model access to user agents, plus it also comes packed with OAuth and HTTP access authentication.
Related
I'm working in Flask on creating a JMML ("Join my mailing list") widget that submits data to an email marketing platform, and the platform follows an OAuth2 flow. The basic flow is:
I create access URL using a the base API URL, an API key, and a redirect URI
The program accesses this URL, and the user of the program is redirected to the marketing platform to log in and grant access.
The marketing platform performs another redirect back to the redirect URI that I provided. The URI is appended with the access token that I need to provide with app POST requests of my JMML. Here's an example of what the returned URI looks like:
http://localhost:5000/redirect_url#access_token=2C1zxo3O0J1yo5Odolypuo9DSmcI
Here's the problem I'm having: I have no idea how, programmatically, to use that final redirect url/uri as a variable in Python.I could make the user copy/paste it into a field, but there's gotta be a better way. I honestly don't even know the terminology for a redirected-redirect like this.
It's pathetic, and I'm lost, but here's what I have so far:
#app.route('/redirect_url')
def redirect_url():
# I have no idea how to actaully get the parameter out of the redirect url.
pass
I've checked the API documentation for the email marketing company's API, but they only provide code tips for handling Oauth2 in Ruby and PHP. Help!
There is a good blog post by Miguel Grinberg, where he describes how to work with OAuth in the flask application. Though I think that workflow will stay the same with any other web application.
Based on this it seems like you should be able to get the access token by getting the variable parameter from the url. I do not have your full code so i cant test, nor have I tried it with an # in the url, but this should work
#app.route('/originalurl')
#app.route('/redirect_url#<access_token>')
def show_user_profile(access_token):
if access_token:
#do work
return redirect(url_for('Anotherview')
return render_template('template.hmtl')
Otherwise we need more info on the api you are using Oauth with
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.)
login_required can be used as decorator in django, but a login.html with user/password is restricted by app.
#login_required
def myview(request):
...
now i want to display a button in login.html to redirect user to other site's oauth flow.
the site fix my callback url static. And user/password are not needed now.
so how to redirect user to last request(maybe post with data), after callback from oauth server?
should session/cookies be used to store request object?
You can attach session information to an anonymous user's session in Django; everybody gets a session cookie, anonymous or not. That data is kept after the user logs in.
If your session data is stored in the database, though, then it will take up more and more space over time, and you will want to have a periodic task that clears out the old sessions.
But should you be saving POST data for later replay?
In certain cases, this may be okay -- when you know for certain that the POST request is idempotent, has already been run once, and that the data is just being used to generate the correct page for the user to see.
You probably shouldn't implement this as a generic solution, though. If a GET request can be constructed that redirects through OAuth and then automatically POSTs as the authenticated user, then you likely have a major CSRF hole on your hands.
The python lib mentioned in OAuth website rauth seems to be simple and best one to use. So, I want to use it in Django and unable to actually implement it.
Here is my issue.
# I do something like this initially
from rauth.service import OAuth2Service
from django.shortcuts import render_to_response
def page(request):
service = OAuth2Service(
consumer_key = "..",
consumer_secret = "...",
.. )
url = service.get_authorize_url(redirect_uri="http://mysite.com/redired-url")
# this url is where the user accepts or not.
# which redirects with authorization code.
return HttpResponseRedirect(url)
Now, when user opens page, it directly redirects and asks user to allow or reject.. If user allows, we get authorization code at redirect-url
To get access token from authorization token,
rauth lib mentions to do so which I have to put under a different view corresponding to redirect-url
data = dict(code='foobar',
grant_type='authorization_code',
redirect_uri='http://example.com/')
token = service.get_access_token('POST', data=data)
The problem is with service object. I created service instance in one view, i need to use it in another view to get access token..
Where I am going wrong..? How to get it done.
Okay there's various ways to handle this in the context of a web app. I would highly recommend taking a look at the Facebook Flask example in the examples dir.
The basic idea is provide an authorization view and a redirect view. You want to have the provider redirect to the redirect view and therein you should do all the stuff you'd expect to be able to do assuming you've been authorized by the user. Otherwise, you should bail out and possibly inform the user as to why.
Now what I typically do is keep the service wrappers in a separate module, not in a view, and then import them into the context I need them. You can do things to initialize them dynamically and such. But reference the link I posted for a simple implementation. I think this should do what you want. I realize it's not Django, but the idioms are pretty close with the simple case of views like this.
Update - Upon further review, I saw a need for clarification. You won't get the access_token until AFTER the user clicks "Yes" on the reddit authentication page. It will then redirect, with a code and state information in the query, to the URI you provided at the beginning of your process.
To receive the OAuth2 tokens posted back in the redirect_uri's view, you will need to get the URL parameters from within the view class/method:
code = request.GET.get('code', '')
This will give you a variable containing the code generated from the first request (it's in the URI as a parameter).
Make sure you check your "state" variable as well, retrieving it the same way, otherwise your security goes out the window.
What you do from there depends on if you're using rauth or praw, but you can use the information gleaned above to generate the appropriate request to get said access token.
Basically, your callback view (redirect_uri) handles all reddit verification and processing. Your initial view, for the most part, either a generated link or a redirect to reddit.com.
I'm building a site on Google App Engine, running python and Django non-rel. Everything is working great for HTML and posting/reading data. But as I'm moving forward I'd like to do many of the updates with AJAX, and eventually also over mobile devices like Android and iPhone.
My pages use django non-rel and my login/logout authentication works great for the HTML. But update information sent over JSON would have to be authenticated that the user can make the changes. I see how doing authentication for just AJAX calls wouldn't be too difficult since your still hitting the website, but what about when throwing in mobile phone authentication?
So I'm new to this, where do I start?
How can I set up services on gae so I can do authenticated CRUD operations? Ideally I'd like to use the exact same REST services for ajax, android, etc.
Python makes this pretty easy, you can just create a decorator method of checking the auth and add the decorator to any method requiring auth credentials.
def admin(handler_method):
"""
This decorator requires admin, 403 if not.
"""
def auth_required(self, *args, **kwargs):
if users.is_current_user_admin():
handler_method(self, *args, **kwargs)
else:
self.error(403)
return auth_required
...
#admin
def crudmethod_update(self, *args, **kwargs):
...
Mind you, this assumes a few things about how you are grabbing user data and such but the principal is the same with any setup. The notion you may be laboring under is that ajax calls are handled somehow differently on the server, but just like any restful method you are really getting the same headers. If you can check the authentication on the standard html request you can quite literally hijack the form submission with an ajax request and get the same result back. You may want to get JSON back instead or a smaller piece of HTML and for that you want to either:
Add something you can check in the request to know that it is an ajax request and adjust accordingly.
Implement an RPC Model for handling ajax requests specifically.
For actually handling authentication you can use the google.appengine.ext users library and ride on the google accounts auth or you can write your own. Writing your own of course means implementing a session mechanism (for retaining state across the user session) and storing the passwords in a hashed and salted state for verification.