Note
This is a security vulnerability but it only exists in Drupal 8 as the access shortcuts
permission does not exist in Drupal 7 so I am disclosing it publicly.
See #1541094: Add 'access shortcuts' permission for proof.
Problem/Motivation
If you have configured your site to expose shortcuts via a block instead of the toolbar users without the access shortcuts
permission will still be able to see shortcuts.
A mitigating factor is that they will only see links that they have access to.
Proposed resolution
Make the shortcuts block not appear at all for users without the access shortcuts
permissions.
Remaining tasks
User interface changes
None.
API changes
None.
Comment | File | Size | Author |
---|---|---|---|
#35 | shortcutsblock_does_not-2449633-35.patch | 2.07 KB | willzyx |
#35 | interdiff-2449633-31-35.txt | 434 bytes | willzyx |
#31 | shortcutsblock_does_not-2449633-31.patch | 2.11 KB | joshi.rohit100 |
#29 | 2449633-28-test-only.patch | 1.4 KB | andypost |
Comments
Comment #1
Anonymous (not verified) CreditAttribution: Anonymous commentedLet's see whether I broke something or not.
Is this something we need to test in the base testclass, or do we add a seperate class?
Comment #2
tstoecklerAwesome that you found
BlockInterface::access()
, I wasn't aware this could be solved so elegantly. I had a look atBlockBase::access()
and that basically just delegates toBlockBase::blockAccess()
but - even though all core block plugins still do their access logic there - that is a relict of the past as the code comment inBlockBase::access()
clearly indicates. See also #2375689: BlockBase::blockAccess() should return AccessResult instead of a bool. Thus, it is correct to overrideaccess()
directly, and notblockAccess()
, awesome!Also awesome that you figured out the
$return_as_object
weirdness correctly.One comment on the actual access checking:
This whole hunk can be replaced with
That is not only a little bit more readble but also has the benefit of setting proper role-based cacheability, so that this check does not need to be repeated each time. (I.e. the
setCacheable(FALSE)
is unnecessary in this case, but if we useallowedIfHasPermission()
we don't need to care about that in the first place because that handles the caching logic for us.)Regarding tests: I would prefer introducing a new
ShortcutsBlockTest
which enables the shortcut block (seeWebTestBase::drupalPlaceBlock()
) and creates two users: one with theaccess shortcuts
permission and one without. And then you can assert that the shortcuts block is only shown for the correct user.Comment #3
joshi.rohit100Attached test only patch
Comment #5
joshi.rohit100Attached test only patch again with block administer permissions.
Comment #7
Anonymous (not verified) CreditAttribution: Anonymous commentedRe #2:
That's a nice tweak! I wasn't too sure on the caching, so I figured never caching was the safest :)
In this patch, I changed the whole chunk including the "$return_as_object weirdness" (lol), since it seems to work in the test. Could you elaborate on why this is needed? Do we need extra coverage?
Re #5:
Nice test! Thanks!
I expanded on your test a bit to have an admin, an editor and a no-rights authenticated user. I did however used the users in the base class, and I'm not fully confident that this was the right thing to do.
Comment #9
dawehner... so this implementation is wrong ... it does not take into account
$return_as_object
, so this should rather implement blockAccess().In general I'm curios whether we should mark blockAccess() as abstract, because each block plugin should at least think about its access.
Comment #10
dawehnerI think yeah needs work :(
Comment #11
joshi.rohit100@dawehner - As per https://www.drupal.org/node/2375689, I am not sure whether we use access() or blockAccess() ?
Comment #12
tstoeckler@dawehner: Currently
blockAccess()
must return abool
so it circumvents the entireAccessResult
logic. That's why I think it's currently preferred to implementaccess()
directly, even though none of the other block plugins in core do it (see also #2). But it would be a nice idea to hide away the$return_as_object
foo inaccess()
and just let block plugins always return anAccessResult
. Would probably need some committer feedback first, whether that's feasible at this point.@pjonckiere: That
$return_as_object
foo is a BC-layer. Various access methods in core used to returnTRUE
/NULL
/FALSE
and it was deemed to disruptive to have them suddenly return anAccessResult
object, which is far superior due to the caching logic. So receiving anAccessResult
object is opt-in, which is why we have that argument. This, however, puts the burden on the implementors of the access logic (you, writing the block access in this case), which is rather unfortunate. So the line that was in patch #1 regarding the$return_as_object
parameter is still needed.Comment #13
Anonymous (not verified) CreditAttribution: Anonymous commentedRe #9: I agree with tstoeckler and joshi.rohit100, see #2375689: BlockBase::blockAccess() should return AccessResult instead of a bool
Re #12: Fair enough. Thanks for the explanation.
Comment #15
tstoecklerAwesome, I think we are almost done here. I just have some suggestions to make the test a little bit more concise, although in terms of test coverage it's already perfect:
This code can be replaced with
$block = $this->drupalPlaceBlock('shortcuts');
.That uses the API instead of the UI to place the block, but that is fine, because we do not need to test that placing blocks works as part of this test. The method returns the block entity so you can then do
$block->label()
in the assertions below.Although it doesn't particularly hurt, I don't think it's necessary to test that an admin user can see the block since we're testing that a "regular" user can see it just below that. So in my opinion these two lines can be removed.
I think the
drupalLogin()
is not necessary here, as anonymous users should not have theaccess shortcuts
permission either. In that case thedrupalLogout()
can just be moved below the comment (and maybe the comment should be adapted). Could you try that?If my comments above are implemented I think this change is no longer necessary.
Great work so far, thanks a lot!
Comment #16
tstoecklerComment #17
tstoecklerComment #18
joshi.rohit100Comment #19
joshi.rohit100thanks @tstoeckle.
I have removed the code from ShortcutTestBase as this is base class for all shortcut related test cases and if we we use block module here, then it will instanciate for all tests and we only need this for just one.
Comment #21
joshi.rohit100complete patch with test.
Comment #23
joshi.rohit100Removed the test for admin user as I think, we just need to see for normal user.
Comment #24
andypostSuppose the plugin should implement blockAccess() so \Drupal\Core\Block\BlockBase::access() will do this work right
Comment #25
joshi.rohit100@andypost - #24 is not clear to me. Can you please provide more detail
Comment #26
joshi.rohit100@andypost - #24 is not clear to me. Can you please provide more detail
Comment #27
andypostthere's 2 different methods to expose access for block, custom block plugins should use protected
blockAccess()
implementation to expose thier accessPS: see
\Drupal\Core\Block\BlockBase::blockAccess
Comment #28
joshi.rohit100Updated as per #27 and I think, @andypost is right as we just here only check the access of block.
Comment #29
andypostLet's make sure that test works
Comment #30
willzyx CreditAttribution: willzyx commentedshould be
return $account->hasPermission('access shortcuts');
Comment #31
joshi.rohit100@willzyx thanks :)
Comment #33
andypostGreat, just need to remove unused "use":
is not needed now
Comment #34
andypost#33
Comment #35
willzyx CreditAttribution: willzyx commentedChanges as for #33
Comment #36
tstoecklerComment #37
alexpottThis issue addresses a major bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 7bf1e5a and pushed to 8.0.x. Thanks!