On my latest journey through the lands of Django CMS, I struggled with some permission issues.
While Django CMS is convenient and a good CMS choice in general, it turns out to have some inconsistencies buried in the permission system.
The requirements I have for the permission system in my current project are:
- All CMS pages should be available only for authenticated users
- Editing shall only be allowed for staff
- Some pages should be only visible to a certain group
These requirements are somehow basic, right?
Django CMS’ places to set permissions
Since Django CMS has a lot of different places where you can set permissions I’ll go through them step by step.
“Login required” in page permissions
There is a useful flag in the page permission form which enables to restrict view-access to the page for logged in users. In my opinion, there are two issues with that:
First, it interferes with the group- and user-based settings. I think it would be better to integrate authenticated users into the “View restrictions” section. Currently, it’s hard to tell which to use when.
Secondly, user- and group based settings are applicable also for child pages, while “Login required” is not, which is inconsistent.
Django CMS setting: CMS_PUBLIC_FOR
The CMS setting
CMS_PUBLIC_FOR offers the following feature when set to
If the user accesses a page which does not have a view restriction, deny access, if he’s not staff.
If set to
"all" it works like:
If the user accesses a page which does not have a view restriction, show it even if he’s anonymous.
That’s nice, but there is no
If the user accesses a page which does not have a view restriction, force him to login, if he’s not authenticated.
That feature would be basically needed to use of Django CMS as an intranet application out-of-the-box.
Users (page) / User groups (page)
As stated in the documentation, you can “easily add users with permissions over CMS page”. The following paragraph says:
“You would be able to create a user with the same set of permissions using the usual Auth.User model, but using Users (page) is more convenient.”
Actually this seems to be the wrong way to go. Django has perfect tools for creating users – why create another one, and even choose another name for it? This leads to confusion for staff and admins and should be removed.
For “User groups (page)” I can hardly tell, because it’s not fully clear what it does: It seems to be a mix of global page permissions and some special user CRUD functionality. In the documentation you find:
“User groups (page) manages the same feature on the group level.”
But this is either confusing or wrong: The group management form has completely other functionality than the user management form. Since there is no further documentation, this feature is somehow useless for me.
Global page permissions
Setting global page permissions gives a certain user or group permissions for all pages. The documentation is pretty poor, but in general, it’s self explaining how it works. It’s a useful feature if you have requirements like “Editors should be able to create pages, but not delete them.” The only problem here is that the global declaration overwrites permissions on page level – this is something I’d not expect.
Django permission: “Can view page”
Another setting that overwrites page-level permission is the Django permission “Can view page”: If this is set for a user or a user group, the page-level settings are also ignored.
How I solved my requirements
First I wrote a custom middleware that redirects all requests to Django CMS pages to the login. Then, I removed the “can view pages” permission from all groups and all global permissions for non-staff.
Finally I removed all view restrictions on the page root and set them only on the particular pages which should be restricted.
My two major findings which seem to be worth a discussion are:
If you give a user or group the Django CMS permission to view restricted pages on a global level, this setting overwrites all page-level restrictions.
If you give a user or group the Django permission “can view page”, this setting overwrites all page-level restrictions.
I think the permission capabilities of Django CMS are great in general, but they follow a false principle when the global rule overwrites the special one; it’s just not intuitive.
If you find something I overlooked, I’d be happy to discuss!