Level Specific Access to pages on Django - django

I currently have a website that has three kinds of permissions:
Active
Staff
SuperUser
What I want to do is limit what a user can view depending on his subaccess level on Driver i.e. Driver has three sub access levels - 100, 200, 300. I was thinking of doing this by
def email_check(user):
return user.accesslevel
#user_passes_test(accesslevel=100)
def my_view(request):
...
How do I add the additional property of the subaccess level to the user model? Is there any other way to implement this? ALso, since this is a an already live project, there are a lot of user on-board already. I'll also need to provide them a default access value.

Your idea to go with user_passes_test looks good to me.
So your main issue is basically how to extend the user model. This topic is covered thoroughly under Django documentation: Customizing authentication.
To sum up, there are mainly two ways to go with. One is to extend your user model with a custom model with an one-to-one relationship with User and any custom fields such as access level.
Alternatively, you can provide with a custom user model and substitute the Django User model, but this seems not appropriate for your case.

Related

Using an alternative model for password reset in Django

Due to the complexities of the application I'm creating, I ended up with three user models. One which is pretty much the normal User which is not used for anything other than admin and two others. I wrote my own set of auth backends to deal with it and it's working well.
Now my problem is having a reset password system. Is there a way to use Django's reset password views while using a custom model?
I've answered your related question about password resets which touches on a lot of similar ground.
I haven't tried password resets with multiple user models myself, but if you look at Django's auth views in django.contrib.auth.views, in PasswordResetConfirmView - the view that handles the reset form - it has a get_user() method which fetches the user model. And the form_valid() method performs user authentication. So if you subclass this view as per my other answer and write your own versions of these methods to handle your non-default user model, that should be the way to go.
I don't know about your specific case, but if you were starting again, the best way would probably be to set the default user (as specified in AUTHOR_USER_MODEL) to an extension of Django's AbstractUser, and from there you can customise your user model with different user types and roles. Apologies if you already did that, and of course changing user models on an existing app is difficult and risky. But I think with that design, one password reset link would cover all users. Here's a good blog post laying out that approach.

Extend Django user model with custom fields, receivers and backend

I am designing a Django application (v1.6) and need to do several things with users:
Add custom fields, such as a foreign key for user department
Trigger database changes when certain fields change. For example, when the user's department changes I need to move inventory in another model out of the old department and into the new. I was planning to use a pre_save receiver to do this.
Define custom permissions, such as a user can only modify rows in a table that are associated with their department.
Eventually I want to integrate the application with our Active Directory server for authentication.
I looked at the options in the documentation and see that there are several options, from extending the user model with a one-to-one relationship to writing a custom user model.
What design should I use to meet all of the above goals?
Take a look at this blog post: it provides all the design principles to achieve your goals.
http://www.roguelynn.com/words/django-custom-user-models/
I would also take a look here for more information about Configurable User Models, if you want to have your own authentication scheme:
http://procrastinatingdev.com/django/using-configurable-user-models-in-django-1-5/
I also found the following reference helpful: http://www.sofokus.com/blogi/custom-user-model/

Django security

hope someone can help me.
I have a stack with Django and tasty pie (I use apikey to authenticate and authorize the users). Let me explain what Im trying to do.
I have several users who can only access their data, so imagine that a user through a rest service access all the rows of the model requestoffer, as follows.
http://127.0.0.1:8001/api/v1/requestoffer/?format=json&username=door1&api_key=84051c6fd1581ad60ffa96bcf5a50d3fc11ccdd3
But I dont want that user access all the requestoffers, I just want him to access the ones he is "proprietary".
Do you have any idea how to do this with either Django or Tastypie?
Did I make myself clear?
If every row belongs to one specific user then you can add it as a foreign key to requestoffer and filter the queryset by the user. Another approach would be to extend Authorization class and implement apply_limits.
class MyAuthorization(DjangoAuthorization):
def apply_limits(self, request, object_list):
if request and hasattr(request, 'user'):
return object_list.filter(requestoffer__user=request.user.id)
return object_list.none()
There are a lot of ways to achieve permission management. Which one suits your needs is totally up to you. One way to achieve this might be to create an 'ownership' relation with the model in question, then create a manager for that model only returning records based on the request. The documentation on model managers is pretty straight forward (and elegant).
To automate the record ownership you could create a CurrentUserField as described in Pro Django, there's also multiple ways to implement that. So a long story short, you should just learn by trial-and-error.

Django Multi-User logins - best approach?

I'm currently developing a Django site in which users can have multiple 'accounts', so that they can seamlessly switch between different public profiles when interacting through the site. What I'm designing is likely to attract multiple registrations per person (and won't be discouraged), I just would like to offer this in such a way as that users can keep the profiles tied together, switch easily and only have to log in once.
The two approaches I've thought up so far include:
One (User model + SiteProfile model) pair and many PublicProfile models per person. AUTH_PROFILE_MODULE is set to point to the SiteProfile model. Issue with this is that I can't easily use per-object permissions: these will be set on the User object and not the public profile, thus permissions to see a page for "PublicProfileA" will also be applied to when the user is masquerading as "PublicProfileB".
One Account model and many (User model + UserProfile model) pairs per person. AUTH_PROFILE_MODULE is set to point to the UserProfile model. This would have the added benefit of the permissions working as intended, and that I can simply have a Custom Backend that will switch users by authenticating a user by if they are currently logged in as another user that has the same Account object as the Foreign Key. Authentication would happen by reading fields on the Account object though, which would mean the password field on every User object would be wasted.
As above, but subclassing Account from User. I've been advised strongly against this though (for reasons unclear).
Is there any pitfalls or better approaches to this? Ultimately, should I use the built-in User model as the one-per-person model that identifies a group of public facing profiles (of which these profiles have a FK back to the User object), or use it as the profile itself, linking back to a single Account object for each person?
Yes, I think the best approach would be to have one and only one User per person and several PublicProfile objects that they can "switch" between. This gives the benefit of only one username/password for them and seems to make the most sense with how Django's auth typically works.

Django role based views?

I'm looking for some input on how others would architect this. I'm going to provide class (django group) based views.
For example, a user's group will determine what views/templates he or she will have access to. I'm thinking of perhaps storing paths to view functions in a table to determine what a user's link bar will consist of. Filter specifications can also be stored to determine what rows will fill these templates.
A good example is a hospital nursing units. Nurses at one unit need not see the entire hospital's patients. They only need to see their patients. Doctors on the same unit need only to see those patients as well, but they should have access to much greater functionality.
Has this been done via some third party application? And how would you approach this problem?
Thanks,
Pete
Django already has a groups and permissions system, which may be sufficient for your purpose.
http://docs.djangoproject.com/en/dev/topics/auth/
Generally in your code you check if a user has a permission. A user has his own permissions and those of the groups he belongs to. You can administer this pretty easily from the admin console.
There are two parts you need to look at.
Check that a user requesting a page
has permission to do so.
Only display links to the user if he
has the permission.
For 1. you can check permissions in a decorator as such:
from django.contrib.auth.decorators import permission_required
#permission_required('polls.can_vote')
def some_view(request):
For 2. the currently logged-in user's permissions are stored in the template variable {{ perms }}. This code checks the same permission as above.
{% if perms.polls.can_vote %}
vote
{% endif %}
To generate a list of links you can iterate over user.get_all_permissions() and fetch the links (or function that generates the link) from a dict:
def more_elaborate_list_of_links_for_a_perm(user):
return ["/link1", ...]
_LINKS = {
'polls.can_vote' : lambda u: ["/user/specific/link/" + u.id],
'polls.can_close': lambda u: ['/static/link/1', 'static/link/2'],
'polls.can_open' : more_elaborate_list_of_links_for_a_perm
}
def gen_links(user):
# get_all_permissions also gets permissions for users groups
perms = user.get_all_permissions()
return sum((_LINKS[p](user) for p in perms if p in _LINKS), [])
There are probably many other approaches.
We had a similar problem. Django's groups aren't REALLY suited to this, but you can shoehorn them in.
The way we did it was as follows:
Every access-controlled object has a ManyToMany relation to the groups table. Each group was used to define a specific type of permission ("can view patient basics", "can edit patient contact info", and so on). Users are added to the groups that they should have permissions for (in your example of seeing only patients in this hospital, you could have a "valley-view-hospital" group).
Then when you go to display a list of records to a user, you filter based on the conjunction of the two groups. A user has to have all the associated group permissions to view a given object.
If your system requires it, you can keep a separate ManyToMany of negative permissions, or separate read/write permissions. You could also define a set of meta-groups (doctor, nurse) that result in your lookup filter retrieving the actual subset of permissions.
As far as your link-bar problem goes, you can generate those programatically using the same system - filter based on the classes of objects the user can see or edit, and then use a get_absolute_url() type function (maybe call it get_index_url()) to return the links for the index of each class of object.
Because all this is fairly complex, you'll probably end up wanting to do some level of caching for these things, but get it working before you bother optimizing. It is possible, and it's less ugly in code than it is in words.
There is a new very interesting project about role based permissions in Django:
http://bitbucket.org/nabucosound/django-rbac
I had a similar problem not too long ago. Our solution did the trick, though it might be too simple for your situation. Like everyone is suggesting, we used the django permission system to control what user interactions with models. However, we didn't just try to group users, we also grouped objects through a GenericForeignKey.
We built a model that linked to itself to allow for hierarchies to be developed.
class Group( models.Model ):
name = models.CharField( ... )
parent = models.ForeignKey( 'self', blank=True, null=True)
content_type = models.ForeignKey( ContentType )
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey( 'content_type', 'object_id' )
...
To make it work, we also created a model to serve as the django User model's user profile. All it contained was a ManyToManyField linked to the Group model above. This allowed us to give users access to zero or more Groups as required. (documentation)
class UserProfile( models.Model ):
user = models.ForeignKey( User, unique=True )
groups = models.ManyToManyField( Group )
...
This gave us the best of both worlds and kept us from trying to shoehorn everything into django's permission system. I'm using this basic setup to control user's access to sports content (some users can access whole leagues, some only one or two conferences, some only have access to individual teams), and it works well in that situation. It could probably be a generalized enough to fit your needs.
If you don't need real per-object ACLs, then you can just use the Django permission system. To get a list of all available permissions:
from django.contrib.auth.models import Permission
perms = Permission.objects.all()
There is an API for other authentication and authorization sources, so you do not need to stick with this permissions table.
You may hack this Django system to fit your needs in terms of this authorization model (RBAC) or you may come up with an ACL-like solution.
On a site for an expert on Pinot Noir wine we created per-object access based on a number of different criteria. If the inbound link had a referer field that matched the domain name of a featured winery, then the user got a 'winery token' which expanded to all articles, tasting notes, etc. related to that winery. We use 'named tokens' for give aways at tasting events and they gave access to specific parts of the site. We even use this to grant certain types of permissions to search engine spiders and then make sure that links that come from those search engines have the same permissions as the spider did (ie. no cloaking games).
The short version is that you can create a class (we called them TokenBuckets which hold Tokens) and each object (on a detail page, or a list page, or whatever) can ask the user's TokenBucket if a certain level of access is allowed.
Basically it's a weird kind of ACL system. It wasn't that hard to create the mechanics. All of the magic is in determining under what circumstances which tokens go into the bucket.
You can use django user roles
https://github.com/dabapps/django-user-roles
This question has been asked in Oct 2009 and the problem still exists in July 2012.
I have searched for a good Role-Based app, and found django-permission as the best result.
Three important features that I needed were Roles, view Decorators and Templatetag; apparently django-permissions has all of them. Read it's docs for it's usage.
The only drawback is that it's under development.
We used a role base system for a similar problem.
Basically users have permissions to assume different roles.
View functions got decorated:
def needs_capability(capability,redirect_to="/cms/"):
def view_func_wrapper(view_func):
def wrapped_view_func(request,*args,**kwargs):
if not request.role._can(capability):
return HttpResponseRedirect(redirect_to)
return view_func(request,*args,**kwargs)
return wrapped_view_func
return view_func_wrapper
The rest of the magic is inside the request.role attribute which got
set inside a context processor. Authenticated users got a Role, for the unwashed masses
a DummyRole.
Access to information was restricted further inside the templates:
{% if not request.role.can.view_all_products %}
Lots of products, yeah!
{% endif %}
Not the cleanest solution in my opinion, but worked as expected.