Remove user's permissions (django) - python

I have an issue with removing permissions to users in view or even in the shell. Let me explain my problem:
I did those tests in the shell:
org = Organisateur.objects.get(user__username__contains="ghj")
content_type = ContentType.objects.get_for_model(Tournoi)
Tournoi is the name of a model
permission_ecriture = 'ecriture_Palaiseau'
permission = Permission.objects.get(content_type=content_type, codename=permission_ecriture)
org.user.user_permissions.remove(permission)`
but when I write:
org.user.has_perm('inscription.ecriture_Palaiseau')`
it returns True
but when I rewrite:
org = Organisateur.objects.get(user__username__contains="ghj")
org.user.has_perm('inscription.ecriture_Palaiseau')`
it returns False
It is really weird. Why does it works like this?
In my views, it seems that the permissions are not removed even if I do write:
org = Organisateur.objects.get(user__username__contains="ghj")
(after removing the permission, the user still has it)
What I want to do is to remove a permission from an user and add another permission to the same user immediately after.
But each time I do that, the user still has the "removed permission"......
Thank you very much
I look forward to hearing from you all soon.

This behavior is expected because permissions are cached. From the Django docs:
Permission caching
The ModelBackend caches permissions on the User object after the first time they need to be fetched for a permissions check. This is typically fine for the request-response cycle since permissions are not typically checked immediately after they are added (in the admin, for example). If you are adding permissions and checking them immediately afterward, in a test or view for example, the easiest solution is to re-fetch the User from the database.

Your code is almost right, you just have forgotten to save your user object at the end!
use user.save()

Related

Handle permission cache in django user model

I stumbled upon a weird behaviour: I add a permission to a user object but the permission check fails.
permission = Permission.objects.get_by_natural_key(app_label='myapp', codename='my_codename', model='mymodel')
user.user_permissions.add(permission)
user.has_permission('myapp.my_codename') # this is False!
I found some posts about user permission caching here and here and the solution seems to be to completely reload the object from the database.
# Request new instance of User
user = get_object_or_404(pk=user_id)
# Now note how the permissions have been updated
user.has_perms('myapp.my_codename') # now it's True
This seems really overkill for me and very un-django-like. Is there really no way to either clear the permission cache oder reload the foreign keys like you can do for an object with refresh_from_db()?
Thanks in advance!
Ronny
You can force the recalculation by deleting the user object's _perm_cache and _user_perm_cache.
permission = Permission.objects.get_by_natural_key(app_label='myapp', codename='my_codename', model='mymodel')
user.user_permissions.add(permission)
user.has_permission('myapp.my_codename') # returns False
del user._perm_cache
del user._user_perm_cache
user.has_permission('myapp.my_codename') # should be True
But this will essentially hit the database again to fetch the updated permissions. Since these are based on internal workings in django and not part of the public API, these cache keys might change in the future, so I would still suggest to just fetch the user again. But that's totally up to you.
The caching is only an issue for you because of the has_perms method. If you follow it all the way down the stack, you eventually end up here. You'll see this method explicitly checking the cache before proceeding.
If you really need to know this user's permissions at this point in time and really don't want to refresh from the DB, then you can check more manually/directly without the has_perm helper method, since this permission .add() is a standard m2m operation and the model field has been updated.
In practice, it's unlikely you'll check a permission right after it is added, while the object is in scope, and while the permissions are cached since it's a bit redundant. I'm sure the Django devs considered this, and decided the benefits of caching it for you by default was the right call.

Listing user associated permission in django 2.2.5

I want to list all the permissions that my user has be it a custom permission or default permission
what I have tried till now
request.user.user_permissions
request.user.get_all_permissions
permissions = Permission.objects.filter(user=request.user)
But none of them returned any permissions though the user was a superuser, staff and active
Any lead and help will be great
An admin user normally has no permissions assigned to them, the .has_perm(…) [Django-doc] will always return True, or as the documentation says:
Returns True if the user has the specified permission, where perm is in the format "<app label>.<permission codename>". (see documentation on permissions). If the user is inactive, this method will always return False. For an active superuser, this method will always return True.
So the admin user is not assigned all permissions (this would also be "error-prone" since later new permissions can pop up, and it would thus require extra logic to add these to the superusers that already exist.

how adding new colum to permission table

i am django new bay, i do a lot search but no result.
i need to add client_id to django permission model ( save and retrieve ), so when saving user permission client_id should saved with permission and when using has_perm it should check permission for current user for current client_id
adding example :
user.user_permissions.add(permiObject, request.session['ClientId'])
in template if i check :
{% if perms.app_name.perm_code %}
this check should be for current ClientId
Django Permission model field is : name, content_type, codename
i need it like this : : name, content_type, codename, client_id
I hate to give such answer, because it is not an answer to you direct question, but it really looks like an XY Problem here.
If I understand you correctly, you want to add permission for each user specific per client ID.
The idea behind the Django permissions is that they are supposed to be created at the time of migration, i.e. before your server ever starts to run. Here you add something unnatural, clients are added at runtime hence you also need to modify permissions at runtime. So it looks like Django permissions is not what you need.
What I would do if I were you is simply add a model for my own permissions and connect it to user via the foreign keys.
For example (pseudo code):
class MyPermission(Model):
name = models.CharField(max_length=10)
client = models.CharField(max_length=10)
user = models.ForeignKey(User, on_delete=models.CASCADE)
Run the migrations, then to add some user a new permission:
user.mypermission_set.create(name="write", client="123")
And to test if user has a permission:
user.mypermission_set.filter(name="write", client="123").exists()
So hope this helps, not exactly the way you wanted but gives the same functionality, if I understood you correctly.
PS: Maybe you will have to define a custom user model, not sure if Django will simply accept using mypermission_set with the standard user model, didn't test it.

Why does the admin site not care about my custom user's permissions?

I started a Django (1.10.3) project with a custom user model, inherited from AbstractBaseUser. A couple of weeks into developing the thing, I saw that I needed more granular permissions for admin users, so I extended my user model with PermissionsMixin, generated and applied migrations, and updated my ModelAdmin.
To try it out I logged in to the admin with my superuser and created a new user with all permissions added manually. When I logged in with that new user, I was greeted by a nice "You don't have permission to edit anything".
So I went to the shell, checked my user's permissions and they were there.
>>> u = User.objects.get(username='new_user')
>>> u.get_all_permissions()
{'admin.add_logentry', ...}
However,
>>> u.has_perm('admin.add_logentry')
False
Now, what has_perm does, if the user is not an active superuser, is to call this:
def _user_has_perm(user, perm, obj):
for backend in auth.get_backends():
if not hasattr(backend, 'has_perm'):
continue
try:
if backend.has_perm(user, perm, obj):
return True
except PermissionDenied:
return False
return False
But,
>>> from django.contrib.auth import get_backends
>>> backend = get_backends()[0] # django.contrib.auth.backends.ModelBackend
>>> backend.has_perm(u, 'admin.add_logentry')
True
So,
Why are user.has_perm(perm) and backend.has_perm(user, perm) returning different values?
And ultimately, how can I get the permissions system to work correctly in this scenario?
I should be ashamed of the actual answer to this. At least I hope there's a lesson to be learned from it. Maybe I can add something along the lines of "always check your own implementations first" to my bug fixing heuristics.
The apparent impossibility of those two methods returning different things led me to inspect if I was actually calling them. It turns out that I completely forgot my own implementation of has_perm, which I absent mindedly created in order for the user model to be compliant with the admin.
This implementation, of course, only checked for superuser status.
I think that Occam fellow was on to something.

Django: Using django.contrib.auth for SAAS ( Users, permissions, etc. )

I'm making a SAAS and I've been asking a slew of questions on here related to the Auth system built in. I'm having trouble understanding the "why" and "how". Primarily I don't understand how it fits in with my SAAS.
I (do) know the following:
You can do this: http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
There are many reasons to use the built in auth system (like security) instead of rolling your own
I (don't) know the following:
class MyUserProfile(models.Model):
"""
Administrator for an Account. Can edit tickets and other stuff.
"""
user = AutoOneToOneField(User, primary_key=True)
account = models.ForeignKey(Account)
dogs_name = models.CharField(max_length=255)
In the previous example, account is just what you'd expect; an entity that's paying to use my software. user is my main concern. Somebody goes to a page and creates a UserProfile with a username and password, etc. When they do this, where does the related User get created? Do I need to create it in my view manually based on the request.POST['username'], etc, and then do
myuserprof = MyUserProfile.create(user=foo_user_just_created, account=foo_account, dogs_name='Spot')
I don't know why but for some reason I feel like I'm missing something. This idea of asking somebody to sign up for an account, and then create a MyUserProfile with a form that asks for the password, username, email, et al, and then in my view creating 2 different objects (MyUserProfile and User) with different parts of the form data. I mean I shouldn't have a User form right? Like I said, I feel like I'm either skipping a step or I'm in the wrong paradigm. I'm not new to Django, but for some reason I have trouble with things that I didn't build (I think it might be a mental problem for real at this point).
Maybe there is a good example of this sort of thing being done on some open source project.
Update: Oops, forgot to mention that in the code above I tried to use AutoOneToOneField from django-annoying, but I have no idea where all the User's attributes get set or how to decide which User object to attach to it. This stuff is driving me crazy.
Also, do I need to use the sites app to do this stuff, and finally does a "super user" have all permissions to everything (I don't want people from Account "Acme" to access account "Microshaft" objects)? Or do they just have all permissions to all views?
Somebody goes to a page and creates a UserProfile with a username and password, etc.
UserProfile doesn't have an username or password field. So it should be somebody goes to a page and create an User. Then, it creates an UserProfile associated to that newly created User.
The question is, how and when do you want this UserProfile instance to be created?
Automatically, whenever a new User is created : use signals, as described in the docs
Automatically, whenever the profile is accessed from an user instance : use AutoOneToOneField, and access the profile using user.userprofile instead of user.get_profile()
Manually. But don't forget an user might have no UserProfile associated yet, so user.get_profile() might raise a DoesNotExist exception.
When they do this, where does the related User get created?
It doesn't. You have to create it explicitely.
This idea of asking somebody to sign up for an account, and then create a MyUserProfile with a form that asks for the password, username, email, et al, and then in my view creating 2 different objects (MyUserProfile and User) with different parts of the form data. I mean I shouldn't have a User form right?
Why not? You want here to create an User and his associated profile in one go, right? You could eventually use directly the POST data, or use a Form to access to the fields, or even better, use 2 ModelForm (one for User, one for UserProfile) that you will process in the same view (maybe this question can help?)
Maybe there is a good example of this sort of thing being done on some open source project.
I suggest you check out django-registration and django-profiles.
Note
You have another way of adding information to an User object, by extending the model itsel. It will allow you to put your extra fields directly in the user model and might be easier for you to understand and use.
I won't dive into details here, have a look at that tutorial for more informations.
Other questions
I tried to use AutoOneToOneField from django-annoying, but I have no idea where all the User's attributes get set or how to decide which User object to attach to it. This stuff is driving me crazy
See above on how to use it. If you feel uncomfortable with it, the best is to follow the documentation, which recommend using a ForeignKey with unique=True in user profiles.
Also, do I need to use the sites app to do this stuff
From the site framework docs : Use it if your single Django installation powers more than one site and you need to differentiate between those sites in some way.
and finally does a "super user" have all permissions to everything (I don't want people from Account "Acme" to access account "Microshaft" objects)?
Again, from the docs, Designates that this user has all permissions without explicitly assigning them. That means that everywhere Django is using the built-in permission system (e.g. default administration pages), a super-user will be authorized.
In views you're writing yourself, or if you tweak some ModelAdmin, it's up to you to decide how you are going to check permissions.

Categories

Resources