How do I apply higher permissions to child pages in Wagtail? - django

I am building an intranet site for my organization with Wagtail and we are in the process of adding a knowledge base. The entire site needs to be restricted to logged-in users, but certain pages need to only be accessible to users in certain groups. For instance, only members of the IT group should be able to access the pages underneath the IT Knowledge Base page.
Currently if I set the top-level page to be accessible only by logged-in users, that permission is applied to every page on the site, and I am barred from setting more specific permissions on any child page. It is imperative that I be able to set more specific permissions on child pages.
I was able to find Wagtail Bug #4277 which seems to indicate that the logic for more specific permissions is implemented but not exposed in the admin UI.
I am not familiar with the inner workings of Wagtail yet, especially how Wagtail permissions intersect with Django permissions. How can I add more specific permissions to child pages?

You can restrict or allow users to view a site. You can also restrict or allow users to do some actions (maybe modifying an article).
To pass these restrictions or allowances django uses groups and permissions. Basically it all is based on permissions but sometimes you want to pass the permission to an entire group rather than passing permissions to users explicitly.
Therefore you could create your it_group. Then you would add the permission, let's call it it_permission to that group. When you then add a user to that group, that user then has all the group permissions. As said you don't need to organize these steps with groups. You could also add a permission, let's call it admin_status to a user directly.
When you build your views there are multiple operators that check for permissions of currently logged in user.
You could decorate your view with the permission-required-operator.
See the example:
from django.contrib.auth.decorators import permission_required
#permission_required('your_user_app.it_permission')
def my_view(request):
# only users with permissions can view this view.

Django and Wagtail are both awful at object authorisation.
For your case, it depends how tight you want to make the security, and how complex the authorization model is.
You can set permissions on a per page basis via the group edit page in the admin menu, any page below will inherit those permissions. The problem with this is that the least restrictive permissions apply and there is no deny option. If they have edit permission on a parent page, they'll have edit permission on the child page.
If you just want a superficial prevention to stop unauthorised people editing all knowledge base pages, you might look at using hooks to assess the permissions of the logged in user.
You can use before_edit_page to check before the page form is rendered for editing and redirect to a notification page if they fail, or use after_page_edit to prevent saving (not very friendly after the editor has spent some time on the page).
For before edit, for a simple one-off case and where there is a class for the KB page, where you want to allow only members of the IT Department and Site Managers groups to have access, it could be something like:
# wagtail_hooks.py
from django.contrib import messages
from django.http import HttpResponseRedirect
from wagtail import hooks
from kb.models import KnowledgeBasePage
#hooks.register("before_create_page")
#hooks.register("before_delete_page")
#hooks.register("before_edit_page")
def check_kb_permissions(request, page, page_class=None):
if (page_class or page.specific_class) == KnowledgeBasePage:
if not request.user.groups.get_queryset().filter(name__in=['Site Managers','IT Department']).exists():
messages.error(
request,
'You do not have permission to add, edit or delete knowledge base articles.\
<br><span style="padding-left:2.3em;">Contact support \
to report this issue</span>'
)
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/admin/'))
If the user fails, they stay on the same page with an error message in red banner at the top of the page.
You can build this out to a more complex authorisation model, matching user groups with models and permissions if need be, rather than the hard coded example above.
This doesn't affect CRUD permissions for programmatic operations, but if your concern is just the editor interface then this works.

Related

How to activate users manually

Django 1.11.2
django-registration-redux==1.6
I'm building an intranet website. And I'd like to control myself whether users are active or not. In Django admin there is such a possibility. But "Active" attribute is set to True automatically when a newly registered user confirms his/her email.
In other words what I'd like to do:
1) Let users register and reset passwords.
2) Admin of the site assigns the new user to a group. Users with the minimum permissions can only view. Special permissions allow edit, delete etc. But the user must be unable even to view anything without approval by the admin.
Now I'm planning to organize can_view permission for every model. The two above conditions will be performed by assigning the user to a group.
Well, this seems to be rather cumbersome. That "Active" attribute in admin is much more elegant. But "Active" is automatically set to True when the user confirms his/her email.
Could you give me a piece of advice here?
While it's tempting, never use is_active to deny permissions. The flag is meant to be equivalent to "deleting a user". That also means the user cannot login (with default authentication backend). So it's not an authorization guard, but an authentication guard.
That said, if you don't grant permissions, users don't have them. So if you implement can_view and set it to guard the relevant models and views, then the user can log in, but cannot see anything you don't want them to (it's convenient for a user to see that she successfully logged in though :) ).
Follow-up question from comments
It's fine to use one global permission that is checked per view. When using class based views, I recommend extending LoginRequiredMixin, tuck a few other goodies in a IntranetCommonMixin and have each view combine it with one of the generic base views. See also my answer here.
The only reason you don't want to do it, is that it's tough to code exceptions on the rule, because the first "object" that says "yes", wins.

Django different admins one panel

First, sorry for my poor english.
I'm trying to make a Django system that supports different admins to get the same admin panel, but showing them different objects, that belong to the same CustomModel.
Example:
First step: --> Login
Seconds step: --> Redirect to admin panel (django.contrib.admin.site)
and.. nothing else.
The problem is that I don't know how to show in that panel the objects that corresponds to the logged admin.
Thanks! Gracias!
This is where Django Permissions enter the picture
Django comes with a simple permissions system. It provides a way to
assign permissions to specific users and groups of users.
It’s used by the Django admin site, but you’re welcome to use it in
your own code.
The Django admin site uses permissions as follows:
Access to view the “add” form and add an object is limited to users
with the “add” permission for that type of object. Access to view the
change list, view the “change” form and change an object is limited to
users with the “change” permission for that type of object. Access to
delete an object is limited to users with the “delete” permission for
that type of object.
If you give a staff user permissions to work with only a certain type of object, that's all that he will see in the admin area.
If you have lots of different admin, you can put them into groups and grant permissions for the groups.

row level permissions with django-guardian - no effect on admin interface observed

I have added row level permissions with django-guardian to my project.
From the set-up it seems everything worked fine:
Guardian specific tables have been created (guardian_groupobjectpermission, guardian_userobjectpermission)
Models with GuardedModelAdmin show the "Object permissions" feature next to "History"
It lets me assign "Add", "Change", "Delete" permissions for users/groups
But assigning (resp. not assigning) permissions shows no impact at all on the admin interface. Every user is allowed to do everything with all objects.
I have tried with
user_can_access_owned_objects_only = True
but this only affects the ability to view objects. Once a user sees it, he can also change and delete it. Regardless what is set in the permissions.
And I followed another discussion suggesting this in the ModelAdmin
def queryset(self, request):
if request.user.is_superuser:
return get_objects_for_user(user=request.user, perms=['change_program'], klass=Program)
But this has a similar effect as above, it only limits the visible items.
I would have hoped to see the admin "save" and "delete" buttons (and functions) listening to django-guardian. Is this a misunderstanding? Or did I simply not walk down the entire road yet?
Thanks for any hint!
R
Guardian allows you to create your own permissions to assign to user/object combinations, but limiting access to resources based on those object permissions still requires you to write code in your views. As such, there is no automatic enforcing within the Admin views. The admin integration is for allowing users with access to the admin interface to manage object-level permissions, see the guardian docs:
http://django-guardian.readthedocs.org/en/latest/userguide/admin-integration.html

django staff users manage their own users only

In my Django app a user can register to the site and receive staff_user privileges from the admin.
After that the staff user can create and manage some other users (normal users) using default django admin site.
Now, I would like to let the staff user see and manage only the users he created from the admin site, I don't want him to see other users created by another staff user.
how can I do that? I imagine I need to modify admin.py right?
Don't modify the admin site.
In general, you have the following tools available:
Create groups
Add users to groups
Create custom permissions on your models, to indicate certain actions
https://docs.djangoproject.com/en/1.4/topics/auth/#custom-permissions
However, what you are asking: Now, I would like to let the staff user see and manage only the users he created from the admin site is not possible in django-admin.
The Django-admin site is only intended as a glorified development tool for fully trusted users, not as a customizable app for end users.
If your project requires an admin site with any of the following ...
Customized administraion functionality.
Exposure to any user that is not completely trusted.
... then I'm afraid you have to create your own custom app.
You can replace the stock UserAdmin with your own which overrides queryset() and does the filtering. The bigger issue is what to filter by. The default User model does not store a "created_by" in the model instance. So you would need to add this information whenever a User is added.
How best to do this depends on your Django version.
Django 1.5 introduced a "Configurable User model" which makes this very easy.
https://docs.djangoproject.com/en/dev/releases/1.5/#configurable-user-model
In earlier versions you would either have to monkeypatch the User model, or store that information in a separate "user profile" attached 1:1 to the User.
https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model
Regarding the trusting of users (which wasn't a topic but I feel the need to comment on thnee's answer) in the Django admin, check out the links in my answer here: Should I use Django's Admin feature?

Admin view access to other normal users in django

How can I give access for the admin views to normal users in django?
Go to the admin site and edit the user. Check the check box (under permissions) where it says:
"Staff status
Designates whether the user can log into this admin site."
You then need to grant them appropriate permissions for them to actually see things in the admin site. That is done just below this checkbox. If you want them to be able to do everything, check the "superuser" checkbox.
Is this what you mean?
Update
The OP actually wants to apply these permissions to a group of users. To do this, go to the admin site > Auth > Groups. Create a new group. Give it the permissions you want the group of users to have. You then need to go to each user and add them to this group. They will also need to be given "staff status" in order to log in to the admin site.
Is that what you are after?