Skip to content

Commit

Permalink
Be precise about permissions.
Browse files Browse the repository at this point in the history
For super users one should display only really assigned permissions
and not simply all permissions. It makes it hard in the admin to
modify per-object permissions for super users otherwise.
  • Loading branch information
mitar authored and brianmay committed Feb 29, 2016
1 parent 4d48401 commit a6a6378
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 38 deletions.
7 changes: 4 additions & 3 deletions guardian/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from guardian.compat import OrderedDict, get_user_model, get_model_name
from guardian.forms import UserObjectPermissionsForm
from guardian.forms import GroupObjectPermissionsForm
from guardian.shortcuts import get_perms
from guardian.shortcuts import get_user_perms
from guardian.shortcuts import get_group_perms
from guardian.shortcuts import get_users_with_perms
from guardian.shortcuts import get_groups_with_perms
from guardian.shortcuts import get_perms_for_model
Expand Down Expand Up @@ -265,7 +266,7 @@ def obj_perms_manage_user_view(self, request, object_pk, user_id):

context = self.get_obj_perms_base_context(request, obj)
context['user_obj'] = user
context['user_perms'] = get_perms(user, obj)
context['user_perms'] = get_user_perms(user, obj)
context['form'] = form

request.current_app = self.admin_site.name
Expand Down Expand Up @@ -323,7 +324,7 @@ def obj_perms_manage_group_view(self, request, object_pk, group_id):

context = self.get_obj_perms_base_context(request, obj)
context['group_obj'] = group
context['group_perms'] = get_perms(group, obj)
context['group_perms'] = get_group_perms(group, obj)
context['form'] = form

request.current_app = self.admin_site.name
Expand Down
96 changes: 63 additions & 33 deletions guardian/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,66 @@ def has_perm(self, perm, obj):
return True
return perm in self.get_perms(obj)

def get_group_filters(self, obj):
User = get_user_model()
ctype = ContentType.objects.get_for_model(obj)

group_model = get_group_obj_perms_model(obj)
group_rel_name = group_model.permission.field.related_query_name()
if self.user:
fieldname = '%s__group__%s' % (
group_rel_name,
User.groups.field.related_query_name(),
)
group_filters = {fieldname: self.user}
else:
group_filters = {'%s__group' % group_rel_name: self.group}
if group_model.objects.is_generic():
group_filters.update({
'%s__content_type' % group_rel_name: ctype,
'%s__object_pk' % group_rel_name: obj.pk,
})
else:
group_filters['%s__content_object' % group_rel_name] = obj

return group_filters

def get_user_filters(self, obj):
ctype = ContentType.objects.get_for_model(obj)
model = get_user_obj_perms_model(obj)
related_name = model.permission.field.related_query_name()

user_filters = {'%s__user' % related_name: self.user}
if model.objects.is_generic():
user_filters.update({
'%s__content_type' % related_name: ctype,
'%s__object_pk' % related_name: obj.pk,
})
else:
user_filters['%s__content_object' % related_name] = obj

return user_filters

def get_user_perms(self, obj):
ctype = ContentType.objects.get_for_model(obj)

perms_qs = Permission.objects.filter(content_type=ctype)
user_filters = self.get_user_filters(obj)
user_perms_qs = perms_qs.filter(**user_filters)
user_perms = user_perms_qs.values_list("codename", flat=True)

return user_perms

def get_group_perms(self, obj):
ctype = ContentType.objects.get_for_model(obj)

perms_qs = Permission.objects.filter(content_type=ctype)
group_filters = self.get_group_filters(obj)
group_perms_qs = perms_qs.filter(**group_filters)
group_perms = group_perms_qs.values_list("codename", flat=True)

return group_perms

def get_perms(self, obj):
"""
Returns list of ``codename``'s of all permissions for given ``obj``.
Expand All @@ -65,53 +125,23 @@ def get_perms(self, obj):
"""
if self.user and not self.user.is_active:
return []
User = get_user_model()
ctype = ContentType.objects.get_for_model(obj)
key = self.get_local_cache_key(obj)
if key not in self._obj_perms_cache:

group_model = get_group_obj_perms_model(obj)
group_rel_name = group_model.permission.field.related_query_name()
if self.user:
fieldname = '%s__group__%s' % (
group_rel_name,
User.groups.field.related_query_name(),
)
group_filters = {fieldname: self.user}
else:
group_filters = {'%s__group' % group_rel_name: self.group}
if group_model.objects.is_generic():
group_filters.update({
'%s__content_type' % group_rel_name: ctype,
'%s__object_pk' % group_rel_name: obj.pk,
})
else:
group_filters['%s__content_object' % group_rel_name] = obj

if self.user and self.user.is_superuser:
perms = list(chain(*Permission.objects
.filter(content_type=ctype)
.values_list("codename")))
elif self.user:
model = get_user_obj_perms_model(obj)
related_name = model.permission.field.related_query_name()
user_filters = {'%s__user' % related_name: self.user}
if model.objects.is_generic():
user_filters.update({
'%s__content_type' % related_name: ctype,
'%s__object_pk' % related_name: obj.pk,
})
else:
user_filters['%s__content_object' % related_name] = obj
perms_qs = Permission.objects.filter(content_type=ctype)
# Query user and group permissions separately and then combine
# the results to avoid a slow query
user_perms_qs = perms_qs.filter(**user_filters)
user_perms = user_perms_qs.values_list("codename", flat=True)
group_perms_qs = perms_qs.filter(**group_filters)
group_perms = group_perms_qs.values_list("codename", flat=True)
user_perms = self.get_user_perms(obj)
group_perms = self.get_group_perms(obj)
perms = list(set(chain(user_perms, group_perms)))
else:
group_filters = self.get_group_filters(obj)
perms = list(set(chain(*Permission.objects
.filter(content_type=ctype)
.filter(**group_filters)
Expand Down
26 changes: 24 additions & 2 deletions guardian/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,24 @@ def get_perms(user_or_group, obj):
return check.get_perms(obj)


def get_user_perms(user, obj):
"""
Returns permissions for given user and object pair, as list of
strings, only those assigned directly for the user.
"""
check = ObjectPermissionChecker(user)
return check.get_user_perms(obj)


def get_group_perms(user_or_group, obj):
"""
Returns permissions for given user/group and object pair, as list of
strings. It returns only those which are inferred through groups.
"""
check = ObjectPermissionChecker(user_or_group)
return check.get_group_perms(obj)


def get_perms_for_model(cls):
"""
Returns queryset of all Permission objects for the given class. It is
Expand Down Expand Up @@ -236,7 +254,11 @@ def get_users_with_perms(obj, attach_perms=False, with_superusers=False,
for user in get_users_with_perms(obj,
with_group_users=with_group_users,
with_superusers=with_superusers):
users[user] = sorted(get_perms(user, obj))
# TODO: Support the case of set with_group_users but not with_superusers.
if with_group_users or with_superusers:
users[user] = sorted(get_perms(user, obj))
else:
users[user] = sorted(get_user_perms(user, obj))
return users


Expand Down Expand Up @@ -288,7 +310,7 @@ def get_groups_with_perms(obj, attach_perms=False):
groups = {}
for group in get_groups_with_perms(obj):
if group not in groups:
groups[group] = sorted(get_perms(group, obj))
groups[group] = sorted(get_group_perms(group, obj))
return groups


Expand Down

0 comments on commit a6a6378

Please sign in to comment.