Problem/Motivation

\Drupal\user\Access\RoleAccessCheck does not provide a reason when it doesn't allow access

Steps to reproduce

Create a route that uses \Drupal\user\Access\RoleAccessCheck for access checking.
Access as a user without that role.
No information is provided in the logs

Proposed resolution

Add a reason when not providing access in \Drupal\user\Access\RoleAccessCheck

Remaining tasks

Patch
Tests

User interface changes

API changes

Data model changes

Release notes snippet

Original report

We have a custom module with a route that uses role-based access requirements. This is an internal-use site and not for public access. The basic site setting for the defaut front page is set to /dashboard.

The error when using role-based access does not indicate the reason.
role-based

After changing to permission based for a test, the reason is reported.
perms-based

I can understand attempted access to a restricted path needs to be logged, but is there a way to exclude or filter out a specific route? We get a lot of users hitting / or /dashboard that are not logged in.

Issue fork drupal-3174996

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

blainelang created an issue. See original summary.

larowlan’s picture

Title: No reason reported by AccessAwareRouter.php on routes using role access » RoleAccessCheck should provide a reason when denying access
Version: 8.9.x-dev » 9.3.x-dev
Category: Bug report » Task
Issue summary: View changes
Issue tags: +Bug Smash Initiative, +Novice

Updated this to be a task.
Updated the issue summary to use the template

amjad1233’s picture

From the initial looks it looks like : web/core/lib/Drupal/Core/Access/AccessManager.php

public function check(...) {
    if (!empty($checks)) {
      $arguments_resolver = $this->argumentsResolverFactory->getArgumentsResolver($route_match, $account, $request);
      $result = AccessResult::allowed();
      foreach ($checks as $service_id) {
       // Note the andIf() here. 
       $result = $result->andIf($this->performCheck($service_id, $arguments_resolver));
      }
    }

Which triggers RoleAccessCheck at core/modules/user/src/Access/RoleAccessCheck.php L:50.

    // If there is no allowed role, give other access checks a chance.
    return AccessResult::neutral()->addCacheContexts(['user.roles']);

Which is returning AccessResult::neutral(**NO_REASON**) without a reason and thus we not getting anything in the logs.

So I will be digging further to see where it denies we could add $reason or something. So in other words we don't know if it's yet denied.

larowlan’s picture

I think it would be worth trying to put a value there in place of *NO REASON* and see if that helps

amjad1233’s picture

Issue tags: +DrupalSouth

@larowlan Could be a good candidate for tomorrow's code sprint hoping to resolve this one.

larowlan’s picture

💯🙌

amjad1233’s picture

Adding $reason certainly did help as I was suspecting. Just don't know if it's a good practice to add $reason in Neutral access requests.

fubarhouse’s picture

I've stepped through the process of testing the proposed change.

1. Set up local environment
2. Create authenticated user without access
3. Create content
4. Attempt to edit content as authenticated user without access
5. Observe error message, log out
6. Log in as admin and observe message log.

Looks great.

fubarhouse’s picture

StatusFileSize
new33.39 KB

Added screenshot of test outcomes.

larowlan’s picture

Left a code review. Will chat with Amjad on zoom about test coverage.

larowlan credited quietone.

larowlan’s picture

Status: Active » Needs review

Crediting quietone who was also on the zoom call at the sprint

larowlan credited longwave.

larowlan’s picture

Status: Needs review » Needs work

Some great suggestions from longwave

andypost’s picture

it needs to update second screenshot as messages are about roles not permissions)

andypost’s picture

Status: Needs work » Needs review

fixed feedback

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

larowlan’s picture

Left a question

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

MR should be updated to 10.1
There are also a number of open threads on 1407 that should be addressed

This seems like a super helpful feature. Is there any security implication?

andypost’s picture

Issue tags: +Needs reroll

Needs new patch or maybe @amjad1233 can change target branch to 10.1.x

amjad1233’s picture

Great suggestion let me get my hands dirty in this one.

smustgrave’s picture

Around to review again if needed. Just wanted to double check that there’s no security issue announcing permissions?

andypost’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new696 bytes
new7.51 KB

re-roll and fix for #19

Open questions are

  1. is secure exposing roles machine names
  2. suggestion to add protected method to generate the reason
amjad1233’s picture

@andypost Thanks for the re-roll. 💪💪💪

I tried and patch applies cleanly and site also builds up fine.

patching file 'core/modules/user/src/Access/RoleAccessCheck.php'
patching file 'core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php'

Regarding Question 1 : I believe we are doing that already at certain places, but I agree with hiding as much as we can. With that said, I will defer question to @larowlan.

Regarding Question 2: I am not sure if this class will only be extended or there will be places where we create new instance of the class... In the later case Protected would fail. I think we should crack this one in #2266817: Deprecate empty AccessInterface and remove usages. May be we explicitly define it's signature in interface.

larowlan’s picture

Status: Needs review » Needs work

1) is secure exposing roles machine names

I think we'd need to load the role and call $role->access('view label') for each one

2) I still like adding a method to simplify the complexity here, nested if/else can be removed with early returns in a new method

paulocs’s picture

StatusFileSize
new7.92 KB
new1.88 KB

Why do we need to use $role->access('view label') in this case? I tried to use it but every route that the user does not have access, $role->access('view label') returns FALSE. The message is not displayed for the user, maybe we don't need the $role->access('view label'). What do you think?

For now I have addressed 28.2 pointed by larowlan.

larowlan’s picture

+++ b/core/modules/user/src/Access/RoleAccessCheck.php
@@ -44,10 +45,37 @@ public function access(Route $route, AccountInterface $account) {
+    else {
+      return sprintf('One of the %s %s %s roles are required', implode(', ', $roles), $condition, $last);

No need for else here, as we return above, even more simplification from the new method 💪

I looked into the permissions question and roles require 'administer permissions' to view their labels, which we're not going to grant here, obviously.

I'll ask around

anchal_gupta’s picture

StatusFileSize
new7.9 KB
new735 bytes

I have uploaded the patch
as per #30 comment.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.