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

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

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:

from django.contrib import messages
from django.http import HttpResponseRedirect
from wagtail import hooks

from kb.models import KnowledgeBasePage

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():
                'You do not have permission to add, edit or delete knowledge base articles.\
                <br><span style="padding-left:2.3em;">Contact <a href="/lalala">support</a> \
                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.

enter image description here

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.

Back to Top