[regression] User roles field access is inconsistent, users with 'administer users' permission can gain full access

Created on 24 January 2017, almost 8 years ago
Updated 2 July 2024, 5 months ago

Problem/Motivation

This is approved as a public security hardening in #25.

Access to modify a users role is handled inconsistently. The user access control handler incorrectly allows users with administer users to modify roles. The account form correctly requires administer permissions to edit roles of a user since it is implementing its own form elements.

The permission administer permissions is meant to be used to assign roles to users, CRUD roles, and to edit permissions grants for each role. Not administer users.

Drupal 7

In Drupal 7, when you go to a users page, you can not edit the roles of the user. Nor can you use the bulk "[Assign/Remove] a role from the selected users" operation on admin/people. Unless you have administer permissions.

Drupal 8

In Drupal 8, if you do not have administer permissions, you also cannot edit the roles when you are on the /user/%/edit page.

However if you have administer users, you can go to /admin/people and use the 'add the XXXX role to the selected users' actions.

This is a problem, because the user with administer users can assign himself the built-in 'Administrator' role. Which gives him all permissions, including the ability to edit permissions.

This effectively makes administer permissions useless.

Proposed resolution

  1. Disallow users without administer permissions to edit the user roles in the user edit form.
  2. Add a mechanism to determine if the current user is allowed to use a specific action. Note that the actual action plugin ::access() method is only a run-time check, checking if the action can be done by the current user, on a specific object/entity. But we need more generic check to see if a user is able to read/access an action before the action starts to be executed. The method could be used, mainly, on views with bulk operation form, where the list of actions should be limited to the actions that the current user is allowed to access.
  3. Use the above check to filter out the add/remove role operations from the bulk operations form on /admin/people view.

Remaining tasks

None.

User interface changes

Users without administer permissions permission will not see anymore:

  • The roles field on user account edit form.
  • The add/remove role actions, in the bulk operations selector, on user administrative page, at /admin/people

API changes

  • The action entity defines now its own access control handler in the annotation, pointing to:\Drupal\system\ActionAccessControlHandler
  • ActionAccessControlHandler::checkAccess() will grant the access to the action, first, if the current user has administer actions permission. If not, will ask the plugin to make a decision.
  • New method ::userAccess() in the plugin ActionInterface interface.
  • ActionBase::userAccess() will return TRUE. In this way we ensure the Backward Compatibility
  • Implement ChangeUserRoleBase::userAccess() by checking the user permission.
  • In \Drupal\views\Plugin\views\field\BulkForm, limit the bulk operation action options based on action entity ::access().

Data model changes

None.

Original report by kevin.dutra

Access to the roles field on the User entity is not handled consistently. This gap has been made possible due to the sort of non-standard approach that the AccountForm takes by providing form elements for fields directly in the form builder instead of using the field system to handle form display with normal widgets. Since it's providing the form elements, it's also setting the #access property, but not in a manner that is consistent with the actual field access. As a result, there is a disconnect between what can be done via the UI and via the REST API for the same user.

The AccountForm only allows access to the roles field for a user with administer permissions.

    $form['account']['roles'] = array(
      '#type' => 'checkboxes',
      '#title' => $this->t('Roles'),
      '#default_value' => (!$register ? $account->getRoles() : array()),
      '#options' => $roles,
      '#access' => $roles && $user->hasPermission('administer permissions'),
    );

However, the UserAccessControlHandler allows anyone with administer users access to the roles field.

    // Administrative users are allowed to edit and view all fields.
    if (!in_array($field_definition->getName(), $explicit_check_fields) && $account->hasPermission('administer users')) {
      return AccessResult::allowed()->cachePerPermissions();
    }

Left to be done

  1. Decide on who should actually have access to the field
  2. Create a patch
🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
User module 

Last updated about 14 hours ago

Created by

🇺🇸United States kevin.dutra

Live updates comments and jobs are added and updated live.
  • Security improvements

    It makes Drupal less vulnerable to abuse or misuse. Note, this is the preferred tag, though the Security tag has a large body of issues tagged to it. Do NOT publicly disclose security vulnerabilities; contact the security team instead. Anyone (whether security team or not) can apply this tag to security improvements that do not directly present a vulnerability e.g. hardening an API to add filtering to reduce a common mistake in contributed modules.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024