Node form delete button not access checked

Created on 15 November 2024, 4 months ago

Problem/Motivation

When an access check is created for the entity.node.delete_form route which prevents the current user from accessing the delete route, the Delete button is still rendered on the node edit form. The button does not work because the access check is ran when the button is clicked. I believe the button should not render at all if the user does not have access, exactly the same way as most links in Drupal work.

Steps to reproduce

- Create an access check. Here is a very simplified version that you would never want to actually use, but demonstrates the problem:

my_module.services.yml

my_module.route_subscriber:
  class: Drupal\my_module\EventSubscriber\RouteSubscriber
  tags:
    - { name: event_subscriber }
my_module.access_check.delete_node_access:
  class: Drupal\my_module\Access\DeleteNodeAccessChecker
  tags:
    - { name: access_check, applies_to: _delete_node_access }

RouteSubscriber.php

<?php


namespace Drupal\my_module\EventSubscriber;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Route subscriber.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    foreach ($collection->all() as $route_name => $route) {
      // Add access check to node delete routes.
      $node_delete_routes = [
        // /node/{node}/delete.
        'entity.node.delete_form',
      ];
      if (in_array($route_name, $node_delete_routes)) {
        $route->setRequirement('_delete_node_access', 'my_module.access_check.delete_node_access::access');
      }
    }
  }

}

DeleteNodeAccessChecker.php

<?php


namespace Drupal\my_module\Access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Session\AccountProxy;
use Symfony\Component\Routing\Route;

/**
 * Access check for Drupal core node delete route.
 *
 * Intended to be run on these routes:
 * - entity.node.delete_form.
 *
 * @see \Drupal\my_module\EventSubscriber\RouteSubscriber
 */
class DeleteNodeAccessChecker implements AccessInterface {

  /**
   * Access callback.
   *
   * @param \Symfony\Component\Routing\Route $route
   *   The Symfony route.
   * @param \Drupal\Core\Routing\RouteMatch $routeMatch
   *   The current route.
   * @param \Drupal\Core\Session\AccountProxy $account
   *   The current user account.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  public function access(Route $route, RouteMatch $routeMatch, AccountProxy $account): AccessResultInterface {
    return AccessResult::forbidden("User does not have permission to delete node.");
  }

}

- Clear caches.
- Edit a node. You will see the Delete button.
- Click the delete button. You will see an "Oops, something went wrong" error message.
- Check wd logs. You will see a "User does not have permission to delete node." access denied log.

Proposed resolution

The rendering of the delete button should depend on whether or not the access check returns allowed or forbidden.

Remaining tasks

User interface changes

API changes

Data model changes

🐛 Bug report
Status

Active

Version

2.0

Component

User interface

Created by

🇺🇸United States maskedjellybean Portland, OR

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @maskedjellybean
  • 🇩🇰Denmark ressa Copenhagen

    Moving issue to Drupal core, per the project page:

    Claro is now part of Drupal core

    All new issues should be filed in the Drupal Core issue queue .

  • 🇮🇳India niranjan_panem Gurugram

    hi @maskedjellybean,

    I created a custom module and added the code mentioned in steps to reproduce in drupal-11, I got below warnings.

    PHP Warning: class_implements(): Class Drupal\modules\access_check_module\access\DeleteNodeAccessChecker does not exist and could not be loaded in /var/www/html/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAccessChecksPass.php on line 46

     Warning: class_implements(): Class Drupal\modules\access_check_module\access\DeleteNodeAccessChecker does not exist and could not be loaded in /var/www/html/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAccessChecksPass.php on line 46
    PHP Fatal error:  Uncaught TypeError: in_array(): Argument #2 ($haystack) must be of type array, false given in /var/www/html/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAccessChecksPass.php

    can you please give information on how you got the issue. if possible, please share screen shot of it.

Production build 0.71.5 2024