Problem/Motivation

    // Setting very low priority to ensure access checks are run after alters.
    $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetAccessCheck', -1000);

Yeah. It's wishful thinking people won't make a mistake with priorities. core has -1024 weight RoutingEvents::ALTER subscribers so if someone takes those as an example, they will not have any access checks set on their routes.

It is very easy to create a bug over entity subscriber priorities. Relevant bug: field ui routes do not have methods set because of how event subscribers are prioritized.

Another relevant bug: we are so very loosely coupled that we ended up with two subscribers trying to decide what is an admin path. They obviously use slightly different logic. Both ended up broken. Different ways broken but broken none the less. RoutePreloader does not take a forced _admin_route into consideration while AdminRouteSubscriber considers paths like administration admin routes instead of just taking admin/* and admin as admin routes and then let the _admin_route option do the rest.

Proposed resolution

Fix the security bug here.

Remaining tasks

File followups for the other two.

User interface changes

API changes

Comments

Status: Needs review » Needs work

The last submitted patch, another_route_tighten.patch, failed testing.

chx’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new22.81 KB

Status: Needs review » Needs work

The last submitted patch, 2: 2351777_2.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
StatusFileSize
new31.72 KB

I think about 5 fails left.

chx’s picture

Issue summary: View changes
chx’s picture

Issue summary: View changes
StatusFileSize
new18.75 KB

Scaled back significantly. Still, the bugs are fixed.

The last submitted patch, 4: 2351777_4.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 6: 2351777_6.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
StatusFileSize
new18.23 KB
fabianx’s picture

Issue tags: +Security, +Secure by default

So my understanding of this issue is:

Core is currently not secure by default as you could easily set a priority that overrides the magic subscriber.

I think access checks as subscribers is a good idea, but having the access system be a subscriber itself is not.

The router is tied to the access system as it is a fundamental principle of Drupals system, so I don't see a problem hardcoding the security model - and having someone replace the whole RouterBuilder if they really need a different model.

while still allowing the flexibility of Access Route Subscribers ourselves.

pwolanin’s picture

So, it does seems like at least the access portion should be hard-coded here, but why don't we start with a patch for just that?

Also, it seems like we should be injecting the AccessManager into the constructor of the RouteBuilder?

catch’s picture

I think we could do with more docs on RouteBuilder::isAdminRoute() just to clarify exactly what the rules are. At one point we wanted paths under admin/* to default to admin, but with the option to override (might have been block preview use case), but not sure if that's still relevant.

Does any of the test coverage removed need refactoring rather than removal?

Otherwise looks like a great change and #10 summarizes the trade-offs very well.

Agree with #11 though - would be easier to review if we split into security and not-security chunks.

dawehner’s picture

Yeah, security is a feature of the routing system, I would not be sure whether admin themes would be one of it. For request formats I would just drop that and keep logic on runtime to fallback to GET, POST.

chx’s picture

Issue summary: View changes
StatusFileSize
new5.43 KB
chx’s picture

Issue summary: View changes

I still think that methods always being an array is better. Also, in general, running code on build time is better than running code runtime no matter how little. But, now that's a followup.

chx’s picture

StatusFileSize
new7.2 KB

Added proper dependency, removed method, added test assertion. Should be ready.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Awesome!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 16: 2351777_16.patch, failed testing.

chx’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new7.71 KB

Eh, forgot to patch services to pass in access manager.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 19: 2351777_19.patch, failed testing.

Status: Needs work » Needs review

Fabianx queued 19: 2351777_19.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 19: 2351777_19.patch, failed testing.

dawehner’s picture

Circular reference detected for service "router.builder", path:          [error]
"router.builder -> access_manager -> router.route_provider ->
router.builder".].

Let's use usual setter injection in that case.

chx’s picture

Why not wait for #2352641: Break router.builder dependency to break the loop?

Status: Needs work » Needs review

chx queued 19: 2351777_19.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 19: 2351777_19.patch, failed testing.

claudiu.cristea’s picture

Issue tags: +Needs reroll
claudiu.cristea’s picture

Issue tags: -Needs reroll
StatusFileSize
new5.75 KB

reroll

claudiu.cristea’s picture

Status: Needs work » Needs review

ah

Status: Needs review » Needs work

The last submitted patch, 28: 2351777-28.patch, failed testing.

claudiu.cristea’s picture

Status: Needs work » Needs review
StatusFileSize
new6.34 KB
new6.17 KB

here we go

chx’s picture

StatusFileSize
new8.26 KB

Thanks so much! One nit: you forgot to delete the AccessRouteSubscriber.

larowlan’s picture

+++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php
@@ -101,14 +107,17 @@ class RouteBuilder implements RouteBuilderInterface {
+  public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler, ControllerResolverInterface $controller_resolver, RouteBuilderIndicatorInterface $route_build_indicator = NULL, CheckProviderInterface $check_provider) {

we need to re-order here, no sense having optional argument before non-optional

Other than that looks rtbc

chx’s picture

StatusFileSize
new8.37 KB
new2.25 KB

I do not see why is that optional but w/e.

larowlan’s picture

Status: Needs review » Reviewed & tested by the community

assuming green - thanks

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 34: 2351777_34.patch, failed testing.

chx’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new1002 bytes
new8.37 KB
larowlan’s picture

+1

dawehner’s picture

+1

fabianx’s picture

RTBC + 1

klausi’s picture

Title: RouteBuilder security model: wishful thinking » Replace AccessRouteSubscriber with built-in checks for security reasons
Issue tags: -Security, -Secure by default +Security improvements

Fixing tags and title.

chx’s picture

Unfollowed.

fabianx’s picture

Title: Replace AccessRouteSubscriber with built-in checks for security reasons » Do not depend on event subscribers for security: Replace AccessRouteSubscriber with build-in checks
Parent issue: » #2357719: [meta] Audit the event subscriber system for security

Tagging a parent issue and re-titling related to the new security initiative

catch’s picture

Status: Reviewed & tested by the community » Fixed

Have been following along with this issue as well as the two sub-issues that sorted out the dependency chain. An implicit dependency that depends on subscriber priority and is always called is both riskier and more obfuscated than just having the explicit dependency here. Committed/pushed to 8.0.x, thanks!

Status: Fixed » Closed (fixed)

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