django-guardian icon indicating copy to clipboard operation
django-guardian copied to clipboard

get_objects_for_user not working

Open SergeyDubovitsky opened this issue 8 years ago • 20 comments

Hi, i have model: app/models.py:

class Cashbox(models.Model):
    ...
    class Meta:
        permissions = (
            ('operation_in', 'IN),
            ('operation_out', 'OUT'),
        )

But I get different results:

>>> user = User.objects.get(pk=1)
>>> cashbox = Cashbox.objects.get(pk=1)
>>> cashbox in get_objects_for_user(user, perms=['app.operation_in', ], klass=Cashbox)
True
>>> user.has_perm('app.operation_in', cashbox)
Fasle

Django 1.9.4 django-guardian 1.4.2

Please help me on this.

SergeyDubovitsky avatar Mar 23 '16 12:03 SergeyDubovitsky

Does the user actually have the permission? Is it global or specific to the cashbox object. A simple set of instructions (e.g. with the example project included) I can use to reproduce the problem would help enormously.

brianmay avatar Mar 26 '16 06:03 brianmay

I'm having this problem too.

levivm avatar Jul 09 '16 23:07 levivm

@levivm , does the user actually have the permission? Is it global or specific to the object. A simple set of instructions (e.g. with the example project included) I can use to reproduce the problem would help enormously.

ad-m avatar Jul 09 '16 23:07 ad-m

get_objects_for_user(self.request.user, 'app.view_myobject') returns all the 'myobject' existing on the database. Even if self.request.user has no permission.

BenDevelopment avatar Aug 30 '16 23:08 BenDevelopment

@BenDevelopment , cannot reproduce. Do you can prepare a test case?

It pass for me (Django 1.10, django-guardian 1, 4, 5) in my app monitorings:

    def test_get_objects_for_user(self):
        # get_objects_for_user(self.request.user, 'app.view_myobject')
        monitoring = MonitoringFactory()
        # No permission -> no object
        qs = get_objects_for_user(self.user, 'monitorings.change_monitoring')
        self.assertFalse(qs.filter(pk=monitoring.pk).exists())

        # Has permission -> object exists
        assign_perm('monitorings.change_monitoring', self.user, monitoring)
        qs = get_objects_for_user(self.user, 'monitorings.change_monitoring')
        self.assertTrue(qs.filter(pk=monitoring.pk).exists())

What misses?

ad-m avatar Aug 30 '16 23:08 ad-m

        object = WorkoutModel(name='test2')
        object.save()
        qs = get_objects_for_user(self.request.user, 'sportapp.view_workoutmodel')
        exists = qs.filter(pk=object.pk).exists()

Exists returns true, and the qs list contains all the 'WorkoutModel' objects of my database

BenDevelopment avatar Aug 31 '16 08:08 BenDevelopment

@BenDevelopment , are you use self.request.user isn't superuser? WorkoutModel use direct foreign key or generic ( https://django-guardian.readthedocs.io/en/stable/userguide/performance.html )? Which django and django-guardian do you use?

ad-m avatar Aug 31 '16 10:08 ad-m

Yes I'm sure self.request.user isn't superuser. I'm using generic solution. Django version : 1.10 django-guardian verions : I use the last development version (clone from this repository). I don't use the last release version because of this issue : https://github.com/django-guardian/django-guardian/issues/453

BenDevelopment avatar Aug 31 '16 11:08 BenDevelopment

I'm experiencing the same issue as @BenDevelopment .

Nijhazer avatar Dec 10 '16 23:12 Nijhazer

@Nijhazer , do you can provide SQL queries? eg.

import logging
l = logging.getLogger('django.db.backends')
l.setLevel(logging.DEBUG)
l.addHandler(logging.StreamHandler())

ad-m avatar Dec 11 '16 00:12 ad-m

Sure. Thanks for the prompt and helpful response.

  1. I have an object type, we'll call it MyModel. There are two objects of this type: summer and winter.
  2. I have a permission called read that is used by MyModel.
  3. I have a group called Summer Group. Using the admin panel, I assigned this group the read permission on summer, but not winter.
  4. I have a user, called Johnny. He does not have any permissions, but he does belong to Summer Group.
  5. objs = get_objects_for_user(request.user, 'my app.read')
  6. Given that request.user is Johnny, I would expect this to return only summer, but it returns both summer and winter.

Debug logs:

(0.003) SELECT "django_content_type"."id", "django_content_type"."app_label", "django_content_type"."model" FROM "django_content_type" INNER JOIN "auth_permission" ON ("django_content_type"."id" = "auth_permission"."content_type_id") WHERE ("auth_permission"."codename" = 'read' AND "django_content_type"."app_label" = 'myapp');

(0.002) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_user_user_permissions" ON ("auth_permission"."id" = "auth_user_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_user_permissions"."user_id" = 3;

(0.003) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_group_permissions" ON ("auth_permission"."id" = "auth_group_permissions"."permission_id") INNER JOIN "auth_group" ON ("auth_group_permissions"."group_id" = "auth_group"."id") INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_groups"."user_id" = 3;

(0.001) SELECT "myapp_mymodel"."id", "myapp_mymodel"."name" FROM "myapp_mymodel";

The third query returns nothing, as auth_group_permissions is empty.

Nijhazer avatar Dec 11 '16 20:12 Nijhazer

Hello,

I tried reproduce your issue, but I can't. Propably I something miss.

Here is a queries which I achieved:

(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_user_user_permissions" ON ("auth_permission"."id" = "auth_user_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_user_permissions"."user_id" = 2; args=(2,)
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_group_permissions" ON ("auth_permission"."id" = "auth_group_permissions"."permission_id") INNER JOIN "auth_group" ON ("auth_group_permissions"."group_id" = "auth_group"."id") INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_groups"."user_id" = 2; args=(2,)
(0.000) SELECT "guardian_userobjectpermission"."object_pk" FROM "guardian_userobjectpermission" INNER JOIN "auth_permission" ON ("guardian_userobjectpermission"."permission_id" = "auth_permission"."id") WHERE ("guardian_userobjectpermission"."user_id" = 2 AND "auth_permission"."content_type_id" = 11 AND "auth_permission"."codename" IN ('change_post')); args=(2, 11, 'change_post')
(0.000) SELECT "guardian_groupobjectpermission"."object_pk" FROM "guardian_groupobjectpermission" INNER JOIN "auth_group" ON ("guardian_groupobjectpermission"."group_id" = "auth_group"."id") INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") INNER JOIN "auth_permission" ON ("guardian_groupobjectpermission"."permission_id" = "auth_permission"."id") WHERE ("auth_user_groups"."user_id" = 2 AND "auth_permission"."codename" IN ('change_post') AND "auth_permission"."content_type_id" = 11); args=(2, 'change_post', 11)

Here is a code of tests: https://github.com/django-guardian/django-guardian/compare/debug-bug-415 Do you can look at it, @Nijhazer? git clone && git checkout && python manage.py test --keepdb guardian.testapp.tests.test_bug.BugTestCase.test_bug_report -v2

ad-m avatar Dec 21 '16 02:12 ad-m

@Nijhazer , @BenDevelopment , do yo use superuser as user with permissions?

ad-m avatar Dec 22 '16 13:12 ad-m

Hi, have you understood this issue? It looks like I also have this problem... get_objects_for_user returns all the model instances, not just the ones for which the user has permissions. I'm using Django 1.10.5 and django-guardian 1.4.8

jfschaff avatar May 18 '17 12:05 jfschaff

@jfschaff , do you user superuser as user with/without permissions? Superuser has all permissions regardless whether you assign it to him or not.

ad-m avatar May 18 '17 13:05 ad-m

@ad-m No, with a normal user I do get all the instances, whatever the permissions.

jfschaff avatar May 18 '17 15:05 jfschaff

I think I have found the root-cause. There are global permissions for the user. There is a parameter 'accept_global_perms' in the function 'get_objects_for_user' If 'accept_global_perms' is True. You may get all the instances. Try to set 'accept_global_perms' to False , then you will get the expected result

climby avatar Oct 17 '17 09:10 climby

I think anyone still having this issue should create a failing test.

doganmeh avatar Jan 16 '18 18:01 doganmeh

I also had this issue at first, before discovering the accept_global_perms option. Why is this option set to True by default? Setting it to False restricts you more and therefore seems like a safer default (I explicitly have it set to False everywhere I use get_objects_for_user).

maistrotoad avatar Feb 12 '19 14:02 maistrotoad

For anyone here waiting for a fix, I d like to point also, that I was able to get the right objects with get_objects_for_user(user, permissions, any_perm=True, accept_global_perms=False) But without specifying also any_perm=True my tests were failing.

tgamushet avatar Sep 01 '22 10:09 tgamushet