Note: This post is over two years old and so the information contained here might be out of date. If you do spot something please leave a comment and we will endeavour to correct.
25th October 2019 - 4 minutes read time
Drupal has a little flaw in its user permission system that allows users to give themselves, or other users, roles that they shouldn't be able to. If the user has the 'administer users' permission this essentially gives them access to alter roles for any user on the system, meaning that they can grand administrator access to any user on the system.
The fix to this involves a couple of actions.
The first to set up user roles in a very specific order from least amount of permission (ie. anonymous) to most amount of permissions. This is actually the default way that Drupal is set up out of the box, but be sure that when adding more roles that you keep to this order. Here is a typical Drupal role administration screen with some other permissions set up.
The second is to create a hook that will alter the user edit screen and hide roles from the user if they don't have the 'administer permissions' permission. With this code in place the user will still be able to visit the user edit screen and alter user roles, but they don't be able to give any user a role that is higher than their own role.
/**
* Implements hook_form_FORM_ID_alter().
*/
function my_module_form_user_form_alter(&$form, FormStateInterface $form_state) {
// Get the current user and their roles (minus 'authenticated').
$user = \Drupal::currentUser();
$userRoles = $user->getRoles(TRUE);
if ($user->hasPermission('administer permissions')) {
// Don't do anything here as the user has the correct permissions.
return;
}
// Extract the role options from the form.
$options = $form['account']['roles']['#options'];
$removeRole = FALSE;
// Remove any roles that are above the user.
foreach ($options as $rid => $option) {
if ($removeRole == TRUE) {
unset($options[$rid]);
}
if (in_array($rid, $userRoles)) {
$removeRole = TRUE;
}
}
// Put the options back into the form.
$form['account']['roles']['#options'] = $options;
$form['account']['roles']['#access'] = $user->hasPermission('administer user roles');
}
The final step is to remove the user role add and remove actions from the People administration view. To do this edit the view at the path /admin/structure/views/view/user_admin_people and edit the field called "User: Bulk update (Bulk update)". In the dialog that appears select the "Available actions" option to "Only selected actions" and then ensure that no role update action is selected. The form in my site looked like this.
With these elements in place you'll have a much more locked down user administration area without too much code to maintain. The only thing you need to be careful of is making sure your roles and permissions are carefully stacked so that users can't give themselves a role that would give them the 'administer permissions' permission. This isn't a massive security flaw as you'll need to allow users the ability to do that.
This is the fourth article in a series of articles about the Batch API in Drupal. The Batch API is a system in Drupal that allows data to be processed in small chunks in order to prevent timeout errors or memory problems.
This is the third article in a series of articles about the Batch API in Drupal. The Batch API is a system in Drupal that allows data to be processed in small chunks in order to prevent timeout errors or memory problems.
This is the second part of a series of articles looking at the Batch API in Drupal. The Batch API is a system in Drupal that allows data to be processed in small chunks in order to prevent timeout errors or memory problems.
Comments
Consider using Role Delegation module instead.
Submitted by Alex Bukach on Fri, 11/19/2021 - 10:16
PermalinkThanks Alex, that module looks like it would do a similar thing. Good to know!
Submitted by giHlZp8M8D on Fri, 11/26/2021 - 11:06
PermalinkAdd new comment