Currently Django Admin is pretty permissive for Admin Actions. That is when an action is created for a ModelAdmin, all of the users with view permissions on that model can run the action. To restrict someone’s use of the action you need to create a permission and then manually add check if the user has that permissions.
Why don’t we have permission system for actions similar to that we have for admin models?
For instance, for a user to be able to run an action (except for the superuser), they should have the corresponding permission. The permissions are created automatically, similar to those for models.
We can make this feature optional, so if someone wants the permissive approach, they can simply ignore it. After all, the least required privilege approach has proved to be effective in many systems.
P.S. if positive, I can work on implementing this functionality
An action can do anything with the selected objects. It could just create an export file as given in one of the examples, or it could delete those objects, or it could change a field in those objects, or it could do something else entirely.
I’m saying this because I don’t know what the “corresponding permission” would necessarily be for each individual action.
Can you provide more detail as to what you’re suggesting, and what it would look like in practice?
Yeah I probably failed to explain what I meant here.
“An action can do anything with the selected objects” that’s what bothers me. Lets have a look at this scenario.
We have a panel made with Django Admin that different users across the company can access, each with their own user (may or may not be a part of a group). So some of that users are just “read only”, for instance from support team, and the only thing they can do is to have a look at the details about the objects. For that adding “Can view …” is enough. There are a few other types of users with similar limited capabilities in admin.
However, there is an action in admin that triggers a critical task and should only be done in extreme cases. It should only be available to superuser and a few other users. But with the current implementation of Admin actions, whichever user gets a “Can view” permission, they can see and run all of the actions on that object.
I know that there is a way to add custom permissions to an actions (or the common ones), but for that you need to create a permission and add the check to the code.
What I was suggesting is to (automatically) create a permission for each action and allow executing the action only when the user has that permission.
I understand that this is not a common case, but still wanted to know what you think.
Restating this for myself to see if I’m really understanding your proposal - please correct me if I’m not getting the idea.
So lets say that we’ve got two actions for a model, “Export CSV” (from the example in the docs) and “Change Expiration Date” - where a particular field in the model gets set across all selected rows.
What I’m understanding you to say then, is that there would be two permissions created (automatically), “export_csv” and “change_expiration_date”. Then there would be an additional ModelAdmin method created, perhaps with a name and calling signature like has_action_permission(request, permission, obj=None) that is called for each selected row to determine whether or not the user has the rights to perform that action. (Or, if obj==None, then the test is for that permission in general.)
So, what do I think?
Interesting idea, I can definitely see the value of the idea behind it.
Not sure the initial implementation needs to be in core - I think I’d like to see the first implementation as a third-party library to see if it garners wide-spread interest.
It would be a relatively long time before it could become a default, since making these permissions mandatory is going to break everyone’s existing actions until they assign that permission to the appropriate roles.
Personally, I don’t see where it has any value for me. The only people with access to the django admin in the systems I work on are the superusers. We don’t use the admin for any routine operations.
Yeah the first part is absolutely right, but I the 2nd part is a bit different. You do not need to create has_action_permission(request, permission, obj=None) method to check for each row, but rather if the user has the permission for that action, for instance change_expiration_date, they can see that action and run it, but if they don’t have it, the action is not shown to them.
Yeah making this as a 3rd party library is actually a good idea, I can try it to see if many people need that.
Regarding the breaking changes, this can be optional and configurable to avoid breaking.
Yeah this is not handy for superusers
Except that doesn’t account for those systems having row-level security.
For example, consider a blogging system where each author has rights over their entries. They may have the authority to alter an expiration date, or even delete their articles, but are not permitted to alter an article written by someone else.
It’s the same reason / logic behind the obj=None parameter for the other built-in ModelAdmin methods such as has_view_permission, has_change_permission, and has_delete_permission.
Yeah that sounds reasonable. So has_action_permission can be optional. You can implement it when needed and just skip when you do not need to have row-level security or any other complex checks.