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.
One of Drupal's strengths is its ability to create communities of users who contribute towards the content of the site. Whether you have an open forum, where users can create their own accounts, or a closed magazine with just a few editors your need to take the security of your users seriously.
Drupal has a quick and convenient way of creating ajax dialogs that gives users the ability to embed links in content that open up dialog boxes when clicked. This is a useful way of presenting a bit of content to a user without them navigating away from the page.
There are a number of different tools that allow you to validate and test a Drupal site. Inspecting your custom code allows you to adhere to coding standards and ensure that you stamp our common coding problems. Adding tests allows you to make certain that the functionality of your Drupal site works correctly.
This year's DrupalCon Europe was hosted between the 17th and 20th of October, in the French city of Lille. My DrupalCon adventure began early on Monday morning when Chris Maiden picked me up to drive to France via the EuroStar train. We arrived in Lille a little after 4pm, which was really good going for a nearly 400+ mile trip.
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 philipnorton42 on Fri, 11/26/2021 - 11:06
PermalinkAdd new comment