Updated: Comment #N

Problem/Motivation

When checking access for a path like "/admin/structure/views", we have no problem, since we can find out the route is views_ui.list
But checking access for a path like "/admin/structure/views/view/frontpage" is a problem, because the actual route is views_ui.edit, but the path is /admin/structure/views/view/{view}, and we have no way to match that.

Proposed resolution

Add a new method to AccessManager that can parse a route name and an array of parameters:

$this->accessManager->checkNamedRoute('views_ui.edit', array('view' => 'frontpage'));

Remaining tasks

N/A

User interface changes

N/A

API changes

API addition: checkNamedRoute() is added to AccessManager

The constructor change to AccessManager is not an API change because it is a service.

Blocked by this:
#2044539: Implement LocalTask plugins for login/password/register tabs
#2056627: Form API autocomplete is broken for routes
#2045267: LocalTaskBase and LocalTaskInterface has to work with routes containing parameters
#2048969: LocalActionBase and LocalActionInterface has to work with routes containing parameters
#2040065: Remove _account from request and use the current user service instead. (partially)
#2040379: Define contextual entity operations through annotation; remove the context property from hook_menu items

Original report by @pwolanin

motivation:

As we move towards a full route-based system, we need to handle access based on route and parameters rather than tying ourselves in knots reconstructing system paths.

The method we are looking to add should take a route name, an array of parameters, and maybe an optional request objects (defaults to the current one in the DIC) - it would then find the route and load any objects needed before passing off to the actual access checks.

For some use cases, this depends on:
#2031487: When replacing the upcasted values in the request attributes array, retain the original raw value too

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pwolanin’s picture

Title: Add a method to the AccessMaanger that only needs a route name and parameters » Add a method to the AccessManager that only needs a route name and parameters

this would be very helpful for local action and local task plugins, and for menu links as we convert those to be route based.

pwolanin’s picture

Issue tags: +MenuSystemRevamp, +WSCCI

The method we are looking to add should take a route name, an array of parameters, and maybe an optional request objects (defaults to the current one in the DIC) - it would then find the route and load any objects needed before passing off to the actual access checks.

pwolanin’s picture

Issue summary: View changes

expand summary

pwolanin’s picture

Status: Active » Needs work
FileSize
2.1 KB

Here's small start.

tim.plunkett’s picture

+++ b/core/lib/Drupal/Core/Access/AccessManager.phpundefined
@@ -108,6 +109,40 @@ protected function applies(Route $route) {
+   *  Returns TRUE if the user has access to the route, otherwise FALSE.

Indented wrong.

+++ b/core/lib/Drupal/Core/Access/AccessManager.phpundefined
@@ -108,6 +109,40 @@ protected function applies(Route $route) {
+      $route = $$this->container->get('router.route_provider')->getRouteByName($route_name, $parameters);

I just had $$this in another issue, certainly didn't work like I wanted :_

pwolanin’s picture

Fixes those little issues, but honestly my head is exploding a bit as I trying to find a simple and efficient code path to take a known route + parameters and check access on it. Using the router code to match the request based on a URL seems totally silly - we already know the route.

pwolanin’s picture

FileSize
3.23 KB

This fleshes out the method code a little more, but it feels like a hack.

dawehner’s picture

Just did a bit of work on the tests, but no real progress.

dawehner’s picture

Some more tracking of work.

dawehner’s picture

Status: Needs work » Needs review
FileSize
6.19 KB
14.07 KB

Completed the test coverage.

Status: Needs review » Needs work

The last submitted patch, access-2046737-10.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
509 bytes
14.09 KB

Oh another one showing a clear lack of sleep.

Crell’s picture

+++ b/core/lib/Drupal/Core/Access/AccessManager.php
@@ -108,6 +151,48 @@ protected function applies(Route $route) {
+        $defaults['account'] = $this->container->get('request')->attributes->get('account');

Shouldn't this be _account now?

dawehner’s picture

FileSize
2.34 KB
14.12 KB

You are totally right.

Thanks for your review!

Crell’s picture

+++ b/core/lib/Drupal/Core/Access/AccessManager.php
@@ -108,6 +151,48 @@ protected function applies(Route $route) {
+    catch (RouteNotFoundException $e) {
+      // Convert to the expected exception.
+      throw new AccessDeniedHttpException();
+    }
+    catch (NotFoundHttpException $e) {
+      // Convert to the expected exception.
+      throw new AccessDeniedHttpException();
+    }

Exceptions are expensive. Something like checkedNamedRoute() should be returning True/False, not exceptioning.

dawehner’s picture

This totally makes sense, especially this is simpler.

dawehner’s picture

This replaces to get the current request to get it from an injected version instead of the container.

catch’s picture

This looks saner but checkNamedRoute() could use some profiling. Have never been keen on mocking the request for every access check and this adds even more setup.

dawehner’s picture

Issue tags: +needs profiling

.

dawehner’s picture

To be honest the DB query to load the route worries me, but there is no way around that.

pwolanin’s picture

@catch - I'm not sure the setup is much more than what's in :
https://api.drupal.org/api/drupal/includes%21menu.inc/function/_menu_lin...

we load all the objects there, etc just in an array rather than a Request object.

dawehner’s picture

I am fine with creating a profile, but I am not sure what really to profile. The complex bits are probably the route naming but that is cached.

dawehner’s picture

#17: access_manager-2046737-17.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, access_manager-2046737-17.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
Issue tags: +MenuSystemRevamp, +WSCCI, +needs profiling

#17: access_manager-2046737-17.patch queued for re-testing.

pwolanin’s picture

Status: Needs review » Reviewed & tested by the community

I think this is ready to go it- it's blocking several other issues for me as well. It's a small actual change and has added tests.

As a follow-up we should consider a flag for the generator to skip aliases at least? We want to make that step of creating the request object as efficient as possible.

tim.plunkett’s picture

tim.plunkett’s picture

Issue summary: View changes

add 2031487

tim.plunkett’s picture

FileSize
14.37 KB

The changes to core.services.yml were next to the newly added CSRF stuff, just a straight reroll.

#22 asks what to even profile here...

catch’s picture

Title: Add a method to the AccessManager that only needs a route name and parameters » Change notice: Add a method to the AccessManager that only needs a route name and parameters
Status: Reviewed & tested by the community » Active
Issue tags: +Needs change record

Well the thing to profile would be when the method gets used a lot of times on the same page. Looks like we've got use cases for this but it's going to be local tasks and contextual links that are the worst which probably isn't so bad. My concern would be if start calling this on regular menu links so in turn create dozens or hundreds of request objects for each access check (not that the performance of that isn't already terrible in general). But we're not doing that yet and might not.

So... committed/pushed to 8.x.

dawehner’s picture

Let's figure out first how to do it for local tasks/actions and then discuss how to do it for menu links, because to be honest menu_item_route_access() is doing that already, so we should try to improve the performance here.

dawehner’s picture

Wrote a changenotice: https://drupal.org/node/2078997

pwolanin’s picture

Title: Change notice: Add a method to the AccessManager that only needs a route name and parameters » Add a method to the AccessManager that only needs a route name and parameters
Status: Active » Fixed

made a few added tweaks, but looks good.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

xjm’s picture

Issue tags: -Needs change record

Untagging. Please remove the tag when the change notification task is completed.

xjm’s picture

Issue summary: View changes

updated