Role-based authorization mechanism for a GAE app - python

I'm looking for a role-based framework/module/package for an app written in Python (2.7) running on Google App Engine.
With role-based I mean a mechanism that would allow me to check (during a request processing most of the time) whether a certain user is able to perform a specific action.
A couple use cases:
user A should be able to see and modify own profile, whereas user B should only be able to see user A profile.
user with an "admin" role should be able to see all registered users, whereas user A and user B should only be able to see users with a public profile (e.g. users with user.public property set to True)
etc.
I'm imagining something like
user_a.is_able_to('read', user_b) # -> True of False
or
user_a.authorize('update', user_b) # raises an exception if 'not allowed to'
So far I've only seen acl.py from tipfy. Looks quite simple and pretty much close to what I'm looking for. I'm wondering whether there's something similar to that acl.py, preferably implemented using NDB.

Web2py contains role based access control which I believe works on GAE. This is documented here:
http://web2py.com/books/default/chapter/29/9
You may be able to fork the auth module and mod it for your purposes. I know people have done this with other parts of web2py such as the DAL.

Turbogears and Web2py frameworks have the role based access control you can integrate one of them on GAE Python version.

Related

Should I disable BroswableAPIRenderer for production environment?

Hi Guys I am deploying a django project to elastic-beanstalk on AWS it currently is working fine, however I would like to know if it's a good or bad practice to allow the BrowsableAPIRenderer to be able to handle requests on my browser, I try to find anything related to it but there is really not too much documentation if not any at all. My App has a really strict permission policy, even when I access through the browsable API, it returns the following:
{
"detail": "Authentication credentials were not provided."
}
however it displays some sort of "information" about the endpoint. It's in that part where I find it difficult to define if I should allow it so that other developers can easily know what is going on, or on the other hand if it is a big risk to be accessible to the public.
You may find this question and its answers useful. Based on this answer, it is true that providing the BrowsableAPIRenderer would help development:
It provides simple UI interface to interact with model objects.
It can provide detailed debugging information.
A list of URLs can be shown in some API root
Based on your current settings, a user would at least need to log on either in DRF login page or Django ADMIN page to see and interact with your API.
You can enable the BrowsableAPI in development but disable it in your production settings following this answer.
In production, I wouldn't want other users, who have write permission, to interact with the APIs via BrowsableAPI. It will force the other users to use the front end app or other secure app to interact with APIs. That would provide a secure layer to forbid descriptive actions done using BrowsableAPI.

apache authentication against django application

I have the following problem:
I wrote an application in Django, basically it’s some kind of management platform for my choir. Now we have some files that we want to provide to our members, but only to them (i.e. registered users). Additionally, there are some files that should only be accessible to the management. Ideally, I want to be able to define in the database who can access which files.
Here is some information about the environment:
Server OS Debian 8.7
Python version 2.7
Django version 1.10
Mod_wsgi version 4.3
What have I tried so far?
Django documentation provides a very, very small example of how to authenticate against the database.
The part where I only validate whether the user is a valid user works. Although it kind of sucks, since the users have to login again every time they access a file.
The part where I validate whether the user is a group doesn't work at all. Apache says:
Unknown Authz provider: group
Then I started to look up this problem, which led me here. When I use the option wsgi-group the apache configuration doesn't cause any problems, but it apparently doesn't validate whether the user is in the specified group either. (I tried to access the file with a user who is not in the specified group and succeeded...)
Now here are some questions I have to this problem:
Has anyone else experienced these problems with the Require group/Require wsgi-group option and has found a solution?
Is there a possibility to "link" the session of the website with the session of the apache file access? As I already mentioned, it is not very user-friendly if the users have to login again every time they want to access a file..
Is there a possibility to write a custom authentication function? Technically, looking at an example implementation for the authentication method check_password (here "auth.wsgi"), I could overwrite this function, provided that the environ variable contains the URL that the user wants to access. (does it?)
This would probably be the most dynamic solution, but I don't quite know if this is possible. The basic idea ist that I render a button in the view for each downloadable file, that sends a POST to the server. The server checks whether the session user has the rights to access this file, and, if true, returns the file. This would mean that the file can only be accessed by the application and not through the apache. Is this possible?
I hope someone can help me, thank you in advance anyways =)
Edit: I did some research and found an answer for my last question here (Having Django serve downloadable files). With the mod_xsendfile this is apparently manageable pretty easily. That leaves just 3 more questions ;)
I have also used X-Send for various purposes within my Django App (usually to serve up files stored in FileFields) but for hosting a suite of static pages such as sphinx-generated pages and supporting media, proxying via X-Send has lead me into more problems than solutions.
As I was researching my own question I discovered yours and realized that mine is the solution to your question #1 and #2: Use mod_wsgi's WSGIAccessScript config with the allow_access(environ, host) function to instantiate a Django WSGI Request which can be programatically distilled to a boolean using whatever business logic you require. I hope someone else can answer my more specific concerns about the approach, but it is functional.
Your question #3 suggests I point you towards Django's Custom Authentication Backend documentation. I have written a custom backend that uses email addresses to authenticate a user rather than requiring users to remember an arbitrary username.
#Django Imports
from django.conf import settings
from django.contrib.auth.models import User
class EmailAuthBackend(object):
"""
Email Authentication Backend
Allows a user to sign in using an email/password pair rather than
a username/password pair.
"""
def authenticate(self, username=None, password=None):
""" Authenticate a user based on email address as the user name. """
try:
user = User.objects.get(email__iexact=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
""" Get a User object from the user_id. """
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None

web service requests authentication django token-api

I want to implement a web service for an iOS application in django.
I need some kind of authentication, and I googled and heard good things about django token-api.
The only thing I don't understand, is how I make sure one authenticated user can not perform actions for another.
For example, If i have a view that has the #token-required, that only promises that a valid token has been sent, however someone can just change the PK in the request itself and make changes for another user.
How do I make sure the user who has the token, can only perform actions for himself?
On a very broad level, you need to distinguish between authentication and authorization. You can read this page as an example, or google it for more, but the basic distinction is that authentication determines that a user is who he says he is, while authorization determines what a certain user is able to see or do.
As you noted above, you can use the django-token-api to help with the authentication issue. But once you've determined that, you need to move to authorization. This is more an issue of permissions that you can see on a per-user (or per-group) basis for individual objects, views, etc.
As Ambroise noted in the comments, using an API framework can make this easier. Here is the django-rest-framework documentation for setting permissions once you have authenticated the user.

How to manage authentication across handler classes in google app engine /w python

Taking into account that I barely know python and am simply following the "hello-world" example here: http://code.google.com/appengine/docs/python/gettingstarted/
I'm unclear as to how I would: use a "MainHandler" class mapped to '/' as a welcome page, ask the user to login and then only allow logged-in users to access a "EditorHandler" class mapped to '/editor'
You've asked a very broad question, and provided no details about what (if any) framework you're planning to use to implement your app. I guess you are probably using webapp?
The basic idea would be to create a login url that you redirect the user to, or you provide to them. If you want them redirected to an edit page on your app, you can specify a dest_url when calling create_login_url:
users.create_login_url(dest_url='/edit')
Within your code you can secure your edit handler easily in app.yaml or with the '#login_required' decorator, depending on how you've setup your app.
This seems to work: http://appengine-cookbook.appspot.com/recipe/login-decorator
Although I dont understand the magic behind most of it, it's probably due to my lack of python skills.
Some comments on that article also point to more "native" solutions:
http://code.google.com/appengine/docs/python/tools/webapp/utilmodule.html

Which openid / oauth library to connect a django project to Google Apps Accounts?

I'm working on an intranet django project (not using GAE) for a company that uses Google Apps for login. So I'd like my users to be able to log in to my django project using their google accounts login. OpenID seems appropriate, although maybe Oauth might work too?
I see a lot of similarly named libraries out there to connect django's auth system to external login systems:
django-authopenid - http://bitbucket.org/benoitc/django-authopenid
django-openid - http://github.com/simonw/django-openid
django-openidauth - http://code.google.com/p/django-openid-auth/
django-oauth - http://bitbucket.org/david/django-oauth
Here's what I'd like to do with the integration: Have users login with their google accounts, instead of the native django system. Keep django's permissions model for things like the admin system. So I think that means automatically creating a new user record in django the first time a new account we haven't seen before logs in.
Can anyone with experience using any of these projects advise me on which would work best? Or just advice on which are most active / functional if you've tried them? Thanks!
I finally got this working, so I'll answer my own question since the previous answers here were helpful but don't tell the whole story.
django-openid-auth is actually quite easy to set up and use. The README file is very clear. If you just want to use standard google accounts (i.e. #gmail.com addresses) then you configure it in settings.py with:
OPENID_SSO_SERVER_URL = 'https://www.google.com/accounts/o8/id'
But if you want to use a "google apps" account, i.e. hosted gmail at your own company's domain, then it's more complicated. I got my details from this question. To use your google apps accounts, configure your settings.py to:
OPENID_SSO_SERVER_URL = 'https://www.google.com/accounts/o8/site-xrds?hd=example.com'
# replace example.com with your hosted google apps domain
In the future this might just work, but today it probably won't. The problem is in python-openid which django-openid-auth relies on. The standard build of python-openid doesn't understand some protocol extensions google is using. (Why does google need to extend the protocol? Dig through http://groups.google.com/group/google-federated-login-api/web/openid-discovery-for-hosted-domains and report back. Good luck.) So you need to instead use adieu's patch to python-openid, which is available here:
http://github.com/adieu/python-openid
Install this over your existing python-openid. Now it should work.
Be careful with the OPENID_USE_AS_ADMIN_LOGIN setting since it requires you to have an openid user account which is 'staff' or 'superuser' to use admin which won't happen by default. So you'll need to do a 2-step process of enabling openid, logging in with your openid to create an account in django, then using your old admin account to mark your own openid account as superuser, and then disabling non-openid admin access.
One more thing: your domain admin might need to enable openid login for your domain before this will work. The control is at http://www.google.com/a/cpanel/example.com/SetupIdp
I've used django-openid-auth. Works fine, can create user account when signing first time. You also can associate openid login with user account in django admin panel.
I know this is a late answer, but I'm doing similar stuff and I just discovered django-socialregistration. which basically does OAuth, OpenID, Facebook Connect, etc. Unlike some of the other options it seems to be actively developed and used by a lot of projects.
I liked that Django socialregistration allowed me to plug in Google Accounts, Facebook, Yahoo and any other OpenID site pretty easily. You just need to give the provider as a link like so:
<img src="{{MEDIA_URL}}/images/yahoo.png"/>
They are all almost identical. I like django-authopenid. It has great documentation and is extremely easy to use. It'll do exactly what you want and do it better than django-openid (which is the only other one I have tried).
HTH

Categories