Problem/Motivation
If you think about any kind of complex rendering you'll realize that access checking is important.
Inside that access checking we have to ensure that the access result metadata is bubbled up as well.
Proposed resolution
Add support for access result objects in #access
On top of that we should also talk about just support access result objects ... as everything else leads potentially to security holes
Remaining tasks
(Up-to-date as of #33.)
Review & Commit.
User interface changes
None.
API changes
#access
in render arrays now accepts AccessResultInterface
objects.
Comment | File | Size | Author |
---|---|---|---|
#44 | interdiff.txt | 1.61 KB | dawehner |
#44 | 2487600-44.patch | 19.11 KB | dawehner |
#34 | interdiff.txt | 3.24 KB | dawehner |
#34 | 2487600-34.patch | 19.02 KB | dawehner |
#31 | interdiff.txt | 11.41 KB | dawehner |
Comments
Comment #1
larowlanComment #2
Wim LeersComment #3
Wim Leers#2495171: Block access results' cacheability metadata is not applied to the render arrays would also benefit from this.
Comment #4
Fabianx CreditAttribution: Fabianx for Acquia commentedIt is enough to set max-age = 0 when encountering a non-access object.
Bad for performance, but good for security.
Comment #5
Wim LeersYep, and
CacheableMetadata::createFromObject()
does exactly that.Comment #6
dawehnerExtracted some of the other issue. It would be interesting whether this causes a lot of various failures.
Comment #7
Wim LeersIf it's an instance of the object, let's pass the object instead?
This should apply the cacheability metadata to
$elements
.Comment #8
fgmAbout 1., could it be like this ? I moved the access calculation out of the loop since it belongs to the element, not its children, so remains constant during the loop.
No idea how to do 2., yet.
Comment #10
Wim LeersFor point 2:
Comment #11
dawehnerI guess these aren't the only instances?
Comment #12
DuaelFrComment #13
Wim LeersFirst, straight reroll — patch no longer applied cleanly.
Comment #14
Wim LeersJust applying #10, and moving the
if (empty($elements))
condition to be the very first thing that is checked.Comment #15
Wim LeersNext steps:
\Drupal\Tests\Core\Render\RendererTest
, specifically::testRenderWithPresetAccess()
,::testRenderWithAccessCallbackCallable()
,::testRenderWithAccessPropertyAndCallback()
and::testRenderWithAccessControllerResolved()
should be expanded to also assert the cacheability metadata, and::providerBoolean()
(which is the data provider for all of them) should be updated to return not only booleans, but alsoAccessResultInterface
objects with cacheability metadata (e.g.AccessResult::allowed()->cachePerUser()
).Comment #18
Wim LeersBumping to critical, discussed at the European D8 criticals meeting, we have agreement that this is critical.
Comment #19
dawehnerLet's also ensure that we use
\Drupal\Core\Render\Element::isVisibleElement
if possible.Comment #21
dawehnerUps, the testbot is pretty fast today.
Comment #23
dawehnerDid a little bit of research why those fail.
It turns out the nodes created for this test don't have promote = 1, which is needed in order to be listed by rss.xml.
This test creates the nodes using the UI, so I could imagine that some of the access logic changes things here.
For a second I was sure the following interdiff would have fixed it
Comment #26
Wim LeersNit: Comment no longer matches the code.
s/$child_denied/$child_access/
This is also the reason for e.g. the
RssTest
failure. Likely more.Nit: comment outdated.
All fixed.
Comment #27
Wim LeersNow test coverage is the only remaining todo.
Comment #28
dawehnerWorking on that test coverage now.
Comment #29
Wim LeersAwesome, thanks! Will review.
Comment #30
alexpottI think this variable is storing the parent's access result so labelling it as
$child_access
is confusing. Also the creation of$access
looks unnecessary.Comment #31
dawehnerYeah its not only that, it also have a wrong logic. It currently inherits AccessResult::allowed() even it did not before with TRUE.
The test coverage written here has covered that.
Comment #32
larowlanThis looks pretty close, couple of candidates for the Uber-nitpick award and a question about a possible DX improvement
Do you think it is worth creating a utility method on Element for this? Element::isVisibleElement could call it too.
nitpick: should be it's
pretty sure phpcs says we should have empty line after each case breaking statement
Nice
Comment #33
Wim LeersIndeed, this looks *very* close. IS updated; the test coverage is complete.
+1
Better :)
Nit: s/FOrm/Form/
Looks very solid :)
Oh wow, I didn't know PHP's
switch
statement supported objects! :DThe provider's name is now a misnomer.
Comment #34
dawehnerNot sure, where this would live? Maybe
AccessResult::checkAllowed($access)
?Its a little bit more tricky: You basically use ==, so this is the reason why the boolean values are checked later.
Went with
providerAccessValues()
Comment #35
Wim Leers¯\(°_o)/¯ — this is fine because it's in a test.
Nit: s/it's/its/ — can be fixed on commit.
Comment #36
Wim Leers#32.2:
No: http://www.elearnenglishlanguage.com/blog/english-mistakes/its/ :) Is the rule perhaps different in Australia?
Comment #37
larowlanYeah I'm just plain wrong, Rtbc +1
Comment #38
catchCouple of nits/questions, generally looks good.
Nit: shouldn't that be indented the same as the line above?
So that make sense, but why's it necessary to add here?
We need a follow-up to update https://api.drupal.org/api/drupal/developer%21topics%21forms_api_referen... in addition to the change record.
Nit, extra blank line.
Needs phpdoc.
Comment #39
Wim Leers#38.2: See the #14 interdiff. Because that code block was affected and the existing code in HEAD doesn't make any sense (checking emptiness not as the first thing), that interdiff just moved it higher so that it actually makes sense again.
Comment #40
Fabianx CreditAttribution: Fabianx for Acquia commentedYes, we need a change record for this, for sure. :)
Comment #41
alexpottNeeds work for #38 and #40
Comment #42
Wim LeersDone: https://www.drupal.org/node/2514588.
Comment #43
Wim Leers#40 is done, #38.2 is also done. Just other points in #38 need to be addressed now (nits + follow-up filed).
Comment #44
dawehnerYeah why not.
No idea where its maintained, but I added that onto #2226275: Update Drupal 8 Form API reference
Comment #45
Wim LeersMissing trailing period. Can be fixed on commit.
Comment #46
catchIsn't that further the other direction?
edit: failed to select right bit in dreditor and can fix on commit anyway.
Comment #47
catchCommitted/pushed to 8.0.x, thanks!
Comment #48
Wim LeersPublished CR: https://www.drupal.org/node/2514588.
Comment #50
Fabianx CreditAttribution: Fabianx for Acquia commentedPost-Commit review:
Same as #2375695-102: Condition plugins should provide cache contexts AND cacheability metadata needs to be exposed I think this clashes very much with #cache.
I think what would need to happen here is (as we cannot add it to a higher-up region), we would need to create an artificial child element containing everything except access.
e.g.
OR push the access to the stack, so that it is available after the element was rendered and cached ...
But caching with the #access information is wrong. (though probably only a major bug)
Comment #51
Fabianx CreditAttribution: Fabianx for Acquia commentedPlease ignore #50:
Discussed in IRC:
- Adding #access metadata that is affecting the element itself to cacheable metadata is correct, because in case we would be doing the access check inside some #pre_render function, we would also bubble it up and create a cache redirect.
=> No bug here.
This is fixed in a correct way.