Posted by xjm

Problem/Motivation

(From #787152: Dynamic permissions cannot be automatically assigned to or removed from roles).

The admin role that comes configured in the standard profile has the following unexpected behaviors:

  1. Permissions of certain (core) modules are not granted to the admin role when these modules are installed.
  2. Permissions for new configuration items are not granted to the admin role.
  3. Permissions introduced in a module update are not granted to the admin role.
  4. Permissions of existing configuration items are not removed (from any role) when the configuration items are removed.

This issue is about point #1 only. Steps to reproduce:

  • Install Drupal using the Standard profile.
  • Visit admin/people/permissions and observe that the administrator role has all permissions are checked for all modules.
  • Enable Book.
  • Visit admin/people/permissions again and observe that its permissions are not checked.

Proposed resolution

See attached patch. (@todo--document it here)

Remaining tasks

Related issues

User interface changes

  • New permissions for a module will now be checked at admin/people/permissions when the module is first installed.

API changes

The following hooks will be added:

  • hook_modules_to_be_installed()
  • hook_modules_to_be_enabled()
  • hook_user_permissions_insert()
  • hook_user_permissions_delete()
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

no_commit_credit’s picture

no_commit_credit’s picture

Issue summary: View changes

updated summary

xjm’s picture

Tagging.

xjm’s picture

Assigned: Unassigned » xjm

And, I'll write a functional test for this.

sun’s picture

Status: Needs review » Needs work

Ugh. The new hook names sound pretty wonky to me.

And, the use-case implementation in User module is even more wonky:

+++ b/core/modules/user/user.module
@@ -3828,21 +3873,31 @@ function user_register_submit($form, &$form_state) {
+function user_modules_to_be_installed($modules) {
+  // Record all currently defined permissions, for later use in
+  // user_modules_installed().
+  $all_permissions = &drupal_static(__FUNCTION__);
+  $all_permissions = array_keys(module_invoke_all('permission'));
+}

This won't work within module updates, since it's entirely based on hooks.

In fact, this will also lead to unexpected results when modules are disabled (after being installed), and one of the newly installed modules defines the same permission as one of the disabled modules.

catch’s picture

David_Rothstein’s picture

Ugh. The new hook names sound pretty wonky to me.

Agreed. We have so many hooks that run when modules are enabled that all the good names were taken :)

This won't work within module updates, since it's entirely based on hooks.

Solving issues with module updates isn't the goal of that code. Or really the goal of this issue anymore, given the way the issues were split...

Although I think the code in the patch actually does help solve it, since that's what functions like user_permissions_insert() and user_permissions_delete() could be used for. As I said in the other issue, I'm not sure we can automate that case further because it doesn't seem like there's any general way to distinguish between a module which added a new permission (which should always be given to the admin role) vs. a module which renamed an existing permission (which should only be given to the admin role, and other roles as well, if they had the old permission).

In fact, this will also lead to unexpected results when modules are disabled (after being installed), and one of the newly installed modules defines the same permission as one of the disabled modules.

I'm not sure I follow that. Is there a specific example of what would happen? As far as I can see, this won't cause any problems that don't already exist as a result of #607238: Permissions are assumed to be unique among modules, but uniqueness is not enforced.

David_Rothstein’s picture

Title: When a new module is installed, its permissions are not granted to the admin role. » When a new module is installed, the admin role doesn't get all new permissions

More accurate title (actually borrowing something closer to the one #787152: Dynamic permissions cannot be automatically assigned to or removed from roles used to have originally).... The module's permissions themselves are always granted to the admin role already. The issue here only occurs for dynamic permissions defined by another module (where the list of permissions changes as a result of the new module is being installed).

If I remember right, the main example that actually has a noticeable effect is that turning on the PHP module does not grant permission to use the new "PHP code" text format to the administrator (since that permission is provided by Filter module). So if you turn on the PHP module as an admin and expect to be able to immediately create a node and use the PHP text format just like user 1 can, you can't because you were never granted permission to use it.

David_Rothstein’s picture

Component: simpletest.module » user.module

Looks like this is in the wrong component too... finger slip somewhere? :)

David_Rothstein’s picture

Issue summary: View changes

Updated issue summary.

xjm’s picture

More that I often forget to fill out the component because there's no - None - option, and I think either my browser or dreditor just uses the component from the last issue I filed, or something. :) Working on the test now.

xjm’s picture

Assigned: xjm » Unassigned

So... suddenly, somehow, I can't reproduce this locally in either 8.x or 7.x. Bit baffled. It was reproducible on a different machine yesterday. (In fact, there's also already test coverage for this exact behavior in UserPermissionsTestCase::testAdministratorRole().

Going to try to confirm on the other machine on Monday (and check if that test fails there). I haven't been able to figure out what the missing link is.

Edit: I also noticed another, unrelated "unexpected behavior" for the administrative role functionality in the process of testing--when you make a new role the administrative role, that role also doesn't get any of the existing permissions.

lokapujya’s picture

I am new to contributing to issue queue. I was attempting to help out with this issue: #1153072: Admin role should always provide all permissions (create a superuser role) (alternate feature proposed for D8) However, I am not sure what the intended behavior should be.

I just noticed this and it might help to be aware of this setting when thinking about this problem:
In Home » Administration » Configuration » People >> Account Settings
exists a section called ADMINISTRATOR ROLE where you can select: disabled, Administrator, or one of the custom roles.

The description says, "This role will be automatically assigned new permissions whenever a module is enabled. Changing this setting will not affect existing permissions."

bartlantz’s picture

Status: Needs work » Needs review
FileSize
6.55 KB
967 bytes

Here's a test for this condition pre-patch and also a patch with the test and the above fix. joestewart, barnettech and tim.plunkett also worked on this at the drupalcon core code sprint.

xjm’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests

Awesome!! Thank you sprinters! The test logic looks good to me. It looks like the bot was stuck, so I requeued both patches on QA.

Meanwhile, a few outstanding things with the patch:

  1. +++ b/core/modules/user/user.api.phpundefined
    @@ -463,5 +463,17 @@ function hook_user_role_delete($role) {
     /**
    + * @todo Document this.
    + */
    +function hook_user_permissions_insert($permissions) {
    +}
    +
    +/**
    + * @todo Document this.
    + */
    +function hook_user_permissions_delete($permissions) {
    +}
    
    +++ b/core/modules/user/user.moduleundefined
    @@ -3067,6 +3067,51 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
    + * @todo: Change documentation since modules don't always have to call it.
    ...
    + * @todo: Change documentation, or make all core modules actually call it.
    

    We still need to add the hook documentation and address these @todo.

  2. +++ b/core/modules/user/user.moduleundefined
    @@ -3067,6 +3067,51 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
    + * Removes no longer available user permissions from the site.
    

    This is a little confusing; perhaps:
    Removes user permissions that are no longer available.

  3. +++ b/core/modules/user/user.moduleundefined
    @@ -3823,9 +3878,15 @@ function user_modules_installed($modules) {
    +  // @todo: This will skip any permissions that are not in the database (i.e.,
    +  //   that are not assigned to any roles). This doesn't matter for our
    +  //   purposes, but in theory it's a problem since user_permissions_delete()
    +  //   invokes a hook which should get the full list of "deleted" permissions.
    

    What are the full implications of this?

  4. +++ b/core/modules/user/user.testundefined
    @@ -1152,8 +1152,12 @@ class UserPermissionsTestCase extends DrupalWebTestCase {
    +    // enable book
    ...
    +    // test general node permission for enabled book module
    

    These should be capitalized and begin with a period. Reference: http://drupal.org/node/1354#inline

  5. +++ b/core/modules/user/user.testundefined
    @@ -1152,8 +1152,12 @@ class UserPermissionsTestCase extends DrupalWebTestCase {
    +    $this->assertTrue(user_access('edit own book content', $this->admin_user), t('The permission for node access was assigned to the administrator role.'));
    

    We can leave the t() off the assertion message here. Reference: http://drupal.org/simpletest-tutorial-drupal7#t

irunflower’s picture

Assigned: Unassigned » irunflower

I'll be working on cleaning this up!

irunflower’s picture

Assigned: irunflower » Unassigned
FileSize
6.92 KB

I cleaned this help, but it still needs work in two places.

In comment #13,
#1

+  // Grant any new permissions to the administration role.
+  $rid = variable_get('user_admin_role', 0);
+  if ($rid && !empty($permissions)) {
+    user_role_grant_permissions($rid, $permissions);
+  }
+}
+
+/**
+ * Removes user permissions that are no longer available.
+ *
+ * Modules should call this function when the list of permissions that the
+ * module provides has changed (for example, a dynamic permission has
+ * disappeared).
+ *
+ * @todo: Change documentation, or make all core modules actually call it.

Didn't quite know what to do - someone make a decision! :)

#3

+++ b/core/modules/user/user.moduleundefined
@@ -3823,9 +3878,15 @@ function user_modules_installed($modules) {
+  // @todo: This will skip any permissions that are not in the database (i.e.,
+  //   that are not assigned to any roles). This doesn't matter for our
+  //   purposes, but in theory it's a problem since user_permissions_delete()
+  //   invokes a hook which should get the full list of "deleted" permissions.

I'm not sure what the full implications are - can someone answer?

Everything else *should* be fixed (or I attempted to). Please look and edit as needed.

irunflower’s picture

Status: Needs work » Needs review
FileSize
6.92 KB

Blah, forgot to set status.

Status: Needs review » Needs work

The last submitted patch, 1454686-write_test_admin_user_get_permissions-15.patch, failed testing.

irunflower’s picture

Status: Needs work » Needs review
FileSize
6.92 KB

Rerolled, but:

patch: **** malformed patch at line 34: /**

Can someone take a look? I can't seem to figure what the issue is...

Status: Needs review » Needs work

The last submitted patch, 1454686-write_test_admin_user_get_permissions-18.patch, failed testing.

irunflower’s picture

Status: Needs work » Needs review
FileSize
6.92 KB

Reroll from 12 - let's try this again..

Status: Needs review » Needs work

The last submitted patch, 1454686-write_test_admin_user_get_permissions-20.patch, failed testing.

irunflower’s picture

Status: Needs work » Needs review
FileSize
6.97 KB

Again...

Questions in #15 still apply. These particular changes were not made.

irunflower’s picture

FileSize
8.15 KB

Interdiff (maybe)?

tim.plunkett’s picture

FileSize
2.61 KB
6.96 KB

So the patch in #22 added + signs before a bunch of lines.

So I rerolled it, and here's an interdiff against #12.

andyceo’s picture

Issue tags: -Needs backport to D7

#24: drupal-1454686-24.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +Needs backport to D7

The last submitted patch, drupal-1454686-24.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
7.51 KB

I'm just rerolling this to get it to apply, but it doesn't seem to make sense anymore, since between the patch in #1 and the next patch in #12, the new hook_modules_to_be_installed() invocation was removed...

Is this still a major bug?

Status: Needs review » Needs work

The last submitted patch, permissions-1454686-27.patch, failed testing.

David_Rothstein’s picture

Priority: Major » Normal

Is this still a major bug?

I don't think so, but happy to be overruled... Lowering priority for now. In practice, I've rarely ever seen a situation where this mattered myself; usually it's just a missing checkbox on the permissions page but one that doesn't matter anyway because it's covered by some other permission that you already have.

The problem I've actually seen more often myself is #3 from the issue summary ("Permissions introduced in a module update are not granted to the admin role") but that's covered by a different issue, not this one.

David_Rothstein’s picture

Oh, I lied, #3 actually is covered (at least partially) by the current patch, since it provides a user_permissions_insert() function that can be used for this purpose.

David_Rothstein’s picture

Issue summary: View changes

Updated issue summary.

xjm’s picture

Issue summary: View changes

Removing myself from the author field so that I can unfollow the issue. --xjm

claudiu.cristea’s picture