Django user get_all_permissions() is empty while user_permissions is set - django

I added some permissions to a user via the admin interface.
From some reason all the perm functions fail, e.g
>>> user.get_all_permissions()
set([])
But accessing the table directly, works:
>>> user.user_permissions.all()
(list of permissions as expected)
What can cause the "get_all_permissions" (and all the perm functions like has_perm()) to fail ?
Thanks

had the same problem. I am guessing that at some point you have used a self-crafted AUTHENTICATION_BACKEND? Most examples on the net of this (INCLUDING THE DJANGO 1.0 DOCUMENTATION!) don't mention that the Backends are responsible for permissions handling as well.
However, no biggie: In whatever backend file your code resides, include this import:
from django.contrib.auth.backends import ModelBackend
Then make sure the Backend you wrote extends ModelBackend, e.g.:
class EmailBackend(ModelBackend):
Should be fine.

In my case it was because of permission caching. I get the user,
added permission to user.user_permissions but user.get_all_permissions was empty set() and user.has_perm was False. This problem is only with shell not admin.
user = User.objects.get(username="User")
permission = Permission.objects.get(
codename="organizations.add_organization",
)
user.user_permissions.add(permission)
user.get_all_permissions() # set()
user.has_perm('organizations.add_organization') # False
I have to add additional line before checking permissions:
user.user_permissions.add(permission)
user = User.objects.get(username="User") # new
user.get_all_permissions()

Related

Django custom permission not being assigned to newly created User

This seems pretty trivial but I can't figure out what I'm doing wrong. I've checked several SO posts that sounded similar but the issue apparently lies elsewhere.
I have a custom permission on my model, can_key, and this is registered properly. When I try to add this permission to a newly created user, it's not added.
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
def create_dummy_user(self, username):
username = 'dummy_user'
user = get_user_model().objects.create(username=username, password='asdf4321')
user.save()
user = get_user_model().objects.get(username=username)
permission = Permission.objects.get(codename="can_key")
print(permission)
user.user_permissions.add(permission)
user = get_user_model().objects.get(username=username)
print(f"{user.username} is_active - {user.is_active}")
print(f"{user.username} has perm {permission.codename} - {user.has_perm(permission)}")
return user
This is the print outputs
test_web | main_app | record case | Can key record case
test_web | dummy_user is_active - True
test_web | dummy_user has perm can_key - False
So the user was created and the permission exists / is retrieved, but the permission isn't being added. Why?
You should change the parameter of has_perm() function with string. It's format is "app_name.codename". So you change the code like below
...
print(f"{user.username} has perm {permission.codename} - {user.has_perm('main_app.can_key')}")
...
You should review Django's permission caching documentation.
click to answer of your question

MultipleObjectsReturned: get() returned more than one Permission -- it returned 2

My tests are failing saying get() returned 2 permissions.. But I have not assigned 2 permissions anywhere. In my views m inheriting PermissionRequiredMixin from django.contrib.auth.mixins and assigning permission. Below is my test setUp code, where error is showing:
def setUp(self):
self.material = MaterialFactory.create()
self.material_reorder = MaterialFactory.create(
opening_stock=500, reorder_qty=1000)
self.user = User.objects.create_user(
'admin', 'lennon#thebeatles.com', 'admin')
self.user.user_permissions.add(
Permission.objects.get(codename="add_material"))
It doesn't matter what you assigned. This line is causing the error
Permission.objects.get(codename="add_material")
It means that you have more than one permission with code name add_material.
To find out what other permissions are names add_material, get into Django console
python manage.py shell
once in there import auth models and check the permissions
from django.contrib.auth.models import *
for p in Permission.objects.filter(codename="add_material")
print(p.pk, p.content_type)
This should tell you what other models registered a permission with the same name.
Adding to the above solution, you can avoid loop and just use a simple code to get other permissions form same code name as:
permissions = Permission.objects.filter(codename='add_material')
print(permissions)

Turn off user social registration in django-allauth?

I noticed looking through the django-allauth templates there's a signup_closed.html users can be redirected to when user registration is closed or disabled. Does anyone who's familiar with that module know if there's a pre-configured setting that can be set in settings.py to turn off new user registration via existing social apps? Or do I need to configure that myself? I've read the full docs for allauth and I don't see any mention of it. Thanks.
Looks like you need to override is_open_for_signup on your adapter.
See the code.
There is no pre-configured setting but it's easy to make one (this is what I do).
# settings.py
# Point to custom account adapter.
ACCOUNT_ADAPTER = 'myproject.myapp.adapter.CustomAccountAdapter'
# A custom variable we created to tell the CustomAccountAdapter whether to
# allow signups.
ACCOUNT_ALLOW_SIGNUPS = False
# myapp/adapter.py
from django.conf import settings
from allauth.account.adapter import DefaultAccountAdapter
class CustomAccountAdapter(DefaultAccountAdapter):
def is_open_for_signup(self, request):
"""
Whether to allow sign ups.
"""
allow_signups = super(
CustomAccountAdapter, self).is_open_for_signup(request)
# Override with setting, otherwise default to super.
return getattr(settings, 'ACCOUNT_ALLOW_SIGNUPS', allow_signups)
This is flexible, especially if you have multiple environments (e.g. staging) and want to allow user registration in staging before setting it live in production.
More information at http://django-allauth.readthedocs.io/en/latest/advanced.html#custom-redirects.
You need to subclass allauth.account.adapter.DefaultAccountAdapter to override is_open_for_signup, and then set ACCOUNT_ADAPTER to your class in settings.py

Django: user.has_perm always true and user is not superuser. Why?

I assigned a permission of a user in my Django 1.5 app.
When I list all user permissions with
In [1]: user.get_all_permissions()
Out[1]: set([u'profile.change_profile'])
I can see one permission (which is correct and wanted). The user is also not a superuser, not an admin.
In [2]: user.is_superuser
Out[2]: False
However, if I try to use user.has_perm, I always get True as a return for any submitted permission request.
In [3]: user.has_perm('random_permission')
Out[3]: True
A behaviour I would expect if the user is a superuser/admin. Why is a non-superuser getting always True for every request? Did I miss any setting?
As mentioned in comment by Thane Brimhall you should check your authentication backends.
You can find this comment on has_perm method of User model in django sources:
Returns True if the user has the specified permission. This method
queries all available auth backends, but returns immediately if any
backend returns True. Thus, a user who has permission from a single
auth backend is assumed to have permission in general.
Also don't forget to check user groups. Default backend checks for user groups permissions thus it may be connected.

can't change user permissions during unittest in django

I've finally decided to make some tests for my apps but I'm stuck on testing if a user can change another user (depends on the type of the user -- I use django-rules to be able to do logical permission checks, but this is not important)
Here's the code I have so far
class RulesAndPermissionsTests(TestCase):
fixtures = ['auth_no_permissions.json', 'profiles.json', 'rules.json']
def setUp(self):
self.c = Client()
self.user = User.objects.get(username="estagiario")
self.non_staff = User.objects.get(username="fisica")
self.admin = User.objects.get(username="admin")
login = self.c.login(username='estagiario', password='estagiario')
def test_can_change_non_staff_users(self):
self.assertFalse(self.user.has_perm('logical_change_user', self.non_staff.profile)) # can't change non staff users without permission
# now add the permission and test it again
self.user.user_permissions.add(Permission.objects.get(codename='change_user'))
print self.user.get_all_permissions() # prints set([])
self.assertTrue(self.user.has_perm('logical_change_user', self.non_staff.profile))
Even after adding the permission, my user still has no permissions. Is this because I'm not allowed to create anything during the tests (is this a bad practice?)? Or does django cache the permissions somehow? If I add the permission at setUp it works, but I wanted to change it during the same test (testing with and without the permission).
Thanks in advance!
If you look at the source code for the ModelBackend, you can see that Django does cache the permissions on the user object.
You could try wiping the cache, but that could break your tests if the caching mechanism changes in future. The easiest thing to do is to refetch the user from the database in your test.
from django.contrib.auth.models import Permission
def test_can_change_non_staff_users(self):
self.assertFalse(self.user.has_perm('logical_change_user', self.non_staff.profile)) # can't change non staff users without permission
# now add the permission and test it again
self.user.user_permissions.add(Permission.objects.get(codename='change_user'))
# refetch user from the database
self.user = User.objects.get(pk=self.user.pk)
print self.user.get_all_permissions() # should now include new permission
self.assertTrue(self.user.has_perm('logical_change_user', self.non_staff.profile))