Problem/Motivation
At the moment it seems LinkFormatter doesn't prevent inaccessible links (e.g: links to unpublished nodes) from being displayed.
Steps to reproduce
- Create a link field in e.g: article nodes
- In "Manage display" use LinkFormatter or LinkSeparateFormatter
- Create an unpublished article node (U)
- Create a published article node (P) and link node U
- As anonymous, we see the link to node U which leads to a 403
Proposed resolution
Some sites may want to render those inaccessible links so I propose to add a setting (checkbox) in the formatter to run access checks.
If it is checked, and the user doesn't have access, the link won't be displayed.
| Comment | File | Size | Author |
|---|---|---|---|
| #32 | 3231247-11.3.x-32.diff | 17.77 KB | herved |
| #32 | 3231247-32.diff | 18.33 KB | herved |
Issue fork drupal-3231247
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
Comment #2
herved commentedFirst draft proposal on the approach.
Tests still todo.
Comment #4
herved commentedTests should pass with this, let's see.
New tests validating the added access_check still todo.
Is this approach decent? It is somewhat similar to what
EntityReferenceFormatterBasedoes.I thought about adding this in the field storage/instance setting but
\Drupal\link\Plugin\Field\FieldType\LinkItemdoesn't have such access check.Only
\Drupal\Core\Field\FieldItemListhas an access check but it applies to the whole item list which wouldn't be viable AFAICS.Another way I think would be to use
#access_callback, similar to what\Drupal\Core\Url::toRenderArraydoes, but then the link field (wrapper) would be rendered, even if all items are inaccessible. The only emptiness check happens in\Drupal\Core\Field\FormatterBase::view.Comment #5
larowlanThis should probably be a private issue, unpublishing
Comment #6
larowlanComment #7
herved commentedHello @larowlan, what does that mean?
Do you consider this as a security issue? (I don't think it is but... idk)
Thanks
Comment #8
avpadernoComment #13
herved commentedNote that I wrote this patch initially with the idea to make it non-disruptive.
If the goal is to apply access checks by default then we may need to reverse the logic.
Though I wonder, is there a reason why
\Drupal\Core\Url::toRenderArrayhas the access check, but\Drupal\Core\Url::toStringdoesn't?Couldn't we include this access check in
toStringby default? Perhaps via an "access" key set to TRUE by default in\Drupal\Core\Url::$optionswhich we can disable if needed?).Comment #14
herved commentedReroll for 10.1.x and adapted the unit tests.
Functional tests are still needed but it would be great to get some feedback on the whole issue/approach before moving forward with that.
As-is, the access check happens in a similar way to
EntityReferenceFormatterBasebut I wonder if this access check should even happen at this level, and in this way (or perhaps using a#pre_renderor#access_callback)...This could extend way beyond link formatters.
Comment #15
herved commentedFixing PHPStan issues.
Comment #16
gregglesrepublishing after discussion that this can be handled in public.
Comment #18
herved commentedMR created (PS: Nightwatch tests seem unstable, I had to re-run).
Please check #4 and #13, I feel like this issue extends beyond link formatters so leaving to needs work...
Here is a static patch from MR for composer.
Comment #19
herved commentedComment #20
herved commentedRebased and moving to review, to get feedback on the approach, thanks.
Comment #21
smustgrave commentedLeft some comments on MR.
Comment #22
herved commentedThanks, though I wasn't looking for a code review yet (tests and upgrade path still todo) but rather opinions on the overall approach / scope as it may extend way beyond link formatters.
See #13.
Comment #23
joachim commentedI am marking the following as duplicates:
- #2938807: Only display internal links to content the user has access to view -- older, but has no code
- #3368223: Link field > Access to internal links is not checked on display. -- more recent, has a MR
- #2968609: Link fields do not check access for entity refs -- older, has a MR, but the MR has not been updated in longer
Code from those issues with MRs should be compared with what is here, in case there are ideas that should be integrated into the MR here.
Participants in all those issues should have credit added here.
Comment #24
joachim commented#3368223: Link field > Access to internal links is not checked on display.'s MR is pretty basic.
#2968609: Link fields do not check access for entity refs's MR has a lot of stuff that isn't here.
1. More work on the URL, e.g.:
Should we be doing that here?
2. More stuff on caching that I've not looked at in depth
3. A functional test (though it could really be a kernel test)
Comment #25
joachim commentedAlso, outputting broken internal links really looks like a bug to me -- one of the duplicate issues filed it as such too.
Comment #26
joachim commentedI've tested the current MR with field data in all forms:
- a path alias to a node: /mynode
- a system path to a node: /node/1
- using the lookup to store the entity
In all cases, the item is skipped when the user doesn't have access, so that's working well!
I don't know about the caching side of things though -- see my comment above.
Comment #28
dcam commentedIn my opinion this isn't a bug. Wanting to link to a page that can give a 403 response, for instance prompting users to authenticate to view content behind a pay wall, is an equally valid use case. That's borne out by the fact that this is made optional with the formatter setting. It isn't only for the sake of backward compatibility. It's because the current behavior is a thing people would actually want to do.
Comment #29
herved commentedI agree with #28, displaying inaccessible URLs is a totally valid use case.
So indeed this is not a bug, and a formatter settings does make sense.
When I created this issue, I was confused why
\Drupal\Core\Url::toRenderArrayhad the access check, but\Drupal\Core\Url::toStringdidn't. But I see now that #3343153: Remove deprecated code from \Drupal\Core\Url removed::toRenderArray.I also agree with all review comments so if anyone wants to address those, please feel free. Or I will find some time later this week.
Cheers.
Comment #30
herved commentedAnswering to #24:
1. If I'm not mistaken, this looks like a crude attempt to check entity access.
AccessManager::checkNamedRouteI used here is a much cleaner alternative.2 & 3. The access cacheability is collected with the current MR here in the formatter, but we indeed still need a test here to validate the access is respected and the cacheability as well if possible.
I'll work on that next.
Comment #32
herved commentedApplied suggestions, attaching MR snapshot and also patch that applies to 11.3.