Problem/Motivation

I observed the following error during functional tests:

TypeError: Drupal\Core\Session\PermissionChecker::hasPermission(): Argument #1 ($permission) must be of type string, null given, called in [...]/core/lib/Drupal/Core/Session/UserSession.php on line 123 in Drupal\Core\Session\PermissionChecker->hasPermission() (line 23 of core/lib/Drupal/Core/Session/PermissionChecker.php).

I have not seen this error in a non-test context.

This is caused because argument 1 of PermissionChecker::hasPermission() must be a string. That can be called with a non-string argument from UserSession::hasPermission(), which does not have its own type declarations, so $permission can be a non-string.

I tried adding the same type declaration to UserSession::hasPermission(). That caused the tests to fail immediately and without an error message that was helpful in tracking down the root cause.

Proposed resolution

Deprecate passing non-strings to UserSession::hasPermission() and User::hasPermission(). See #19.

In a followup cast $permission to string so that the the function signature of UserSession::hasPermission() can stay the same and the function signature of PermissionChecker::hasPermission() will always be followed.

Remaining tasks

User interface changes

None.

API changes

None.

Data model changes

None.

Release notes snippet

Issue fork drupal-3410098

Command icon 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

Liam Morland created an issue. See original summary.

liam morland’s picture

Assigned: liam morland » Unassigned
Status: Active » Needs review
StatusFileSize
new580 bytes
andypost’s picture

I bet it's won't fix because the calling code must be fixed instead of core

andypost’s picture

Alternatively it could use to add deprecation when UserSession::hasPermission() is called with non-string argument

liam morland’s picture

Status: Needs review » Closed (duplicate)
Related issues: +#3409223: Pass only strings to UserSession::hasPermission()
liam morland’s picture

Yes, that would make sense. It look like my issue specifically is caused by the issue linked above. But there may be other issues like this. This is, in effect, a change in Drupal's API. UserSession::hasPermission() must now be passed a string when it did not enforce that before.

andypost’s picture

Title: TypeError: PermissionChecker::hasPermission(): $permission must be of type string » UserSession::hasPermission() and User::hasPermission() should type-hint $permission to string
Status: Closed (duplicate) » Needs review
Issue tags: +@deprecated
Parent issue: #3347873: Centralize permission checks in a service » #3050720: [Meta] Implement strict typing in existing code
Related issues: +#3347873: Centralize permission checks in a service
StatusFileSize
new1.54 KB

Kind of it, reopening as bug possible and re-title

will need change record and test and re-parented

smustgrave’s picture

Status: Needs review » Needs work

Seems to have caused some test failures in DrupalCI.

pgn5qs’s picture

This has broken my site. It started with upgrade to 10.2.0 and now any user that isn't the root user (1) get's this message when logging on. Ideas?

TypeError: Drupal\Core\Session\PermissionChecker::hasPermission(): Argument #1 ($permission) must be of type string, null given, called in /Users/*****/Sites/public_html/web/core/lib/Drupal/Core/Session/UserSession.php on line 123 in

Drupal\Core\Session\PermissionChecker->hasPermission() (line 23 of core/lib/Drupal/Core/Session/PermissionChecker.php).
Drupal\Core\Session\UserSession->hasPermission(NULL) (Line: 121)
Drupal\Core\Session\AccountProxy->hasPermission(NULL) (Line: 212)
form_mode_control_control_access_form_mode(Array, 'creation', NULL, Object, 'contact_message.contact_sales.', Object, Array) (Line: 40)
form_mode_control_entity_form_display_alter(Object, Array, NULL) (Line: 545)
Drupal\Core\Extension\ModuleHandler->alter('entity_form_display', Object, Array) (Line: 133)
Drupal\Core\Entity\Entity\EntityFormDisplay::collectRenderDisplay(Object, 'default') (Line: 284)
Drupal\Core\Entity\ContentEntityForm->init(Object) (Line: 97)
Drupal\Core\Entity\EntityForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 536)
Drupal\Core\Form\FormBuilder->retrieveForm('contact_message_contact_sales_form', Object) (Line: 283)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 48)
Drupal\Core\Entity\EntityFormBuilder->getForm(Object) (Line: 86)
Drupal\contact\Controller\ContactController->contactSitePage(Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 627)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 704)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Akhil Babu made their first commit to this issue’s fork.

akhil babu’s picture

Test failures in patch #7 look strange

/tmp/build_workspace_04dcabf34eade6f2685220200c46ced7IA9qsD/core/lib/Drupal
/Component/Serialization/vendor does not exist and could not be created:
Failed to create "/tmp/build_workspace_7f381338ba97106e55c4fb8ea08a06c6Eeef
Dz/core/lib/Drupal/Component/Render/vendor/drupal/core-utility": mkdir(): N
o space left on device

Creating a new MR with same changes to see the actual tests that are failing

akhil babu’s picture

No failed tests

akhil babu’s picture

We probably need a test to confirm the deprecation message. But I am not able to find a 'realistic' scenario where a non string value would be passed as an argument to hasPermission(). The proposed solution is to simply cast $permission to string. The only option to create a failing test for this approach is to call hasPermission() with NULL. If hasPermission is called with an array to create a failing test like hasPermission(['access content']), then deprecation warning will get triggered, but the logic will fail (Array to string conversion).

Moving to needs review for suggestions

akhil babu’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Can probably create a kernel test and call the function.

Also trigger_errors shouldn't points to the ticket but a change record.

andypost’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Deprecation looks good. CR reads fine too.

catch’s picture

Title: UserSession::hasPermission() and User::hasPermission() should type-hint $permission to string » Deprecate passing non-strings to UserSession::hasPermission() and User::hasPermission()
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs followup

The MR doesn't match the issue title - we're deprecating passing a non-string to ::hasPermission() but not adding the type hint yet.

To add the type hint, we'd need to add it to AccountInterface::hasPermission(), this will require using the mechanism documented at https://www.drupal.org/about/core/policies/core-change-policies/drupal-d... - however, we've only actually done that at most once or twice I think so far.

Given this is a bugfix, I think we should just add the cast here with an inline comment, and then open a follow-up to do the full deprecation and type hinting process.

liam morland’s picture

@#14 I encountered this problem when the value passed was NULL. It worked as before when cast to string.

kristiaanvandeneynde’s picture

The documentation for adding the typehint seems wrong? it says:

Or, change the typehint of an argument. For example:

-  public function foo(string $bar);
+  public function foo(/* string|Stringable $bar */);

But shouldn't that be:

-  public function foo(string $bar);
+  public function foo(/* string|Stringable */$bar);

As it stands the documentation seems to want you to temporarily remove the argument by commenting it out.

andypost’s picture

I see no reason to cast as interface expects string, so added type-hints as deprecation already is here

kristiaanvandeneynde’s picture

Status: Needs work » Needs review

Looks good to me, but waiting for a second approval because of my assumption that the deprecation docs are slightly incorrect.

smustgrave’s picture

#19 mentions a follow up, could that be created, then can mark it.

kristiaanvandeneynde’s picture

Issue tags: -Needs followup

Created a child issue and tagged it

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Sorry @kristiaanvandeneynde for this following off my radar. Marking.

quietone’s picture

quietone’s picture

Issue summary: View changes

I'm triaging RTBC issues. I read the IS, the comments for this issue and the followup and the MR for this issue. I don't see any unanswered questions.

The proposed resolution is not correct. I have updated it.

What I did find that needs work is the follow up. The issue summary over there is too brief. If I had not read this issue first I would have no idea what is to be done in that issue. I will tag that issue for an issue summary update.

Leaving at RTBC

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I'm not sure why we're suggesting Stringable in the future typehint. As far as I can see it'll be wrong.

kristiaanvandeneynde’s picture

Yeah that will be wrong, I think the author perhaps got confused because the example we linked to makes mention of Stringable too?

shalini_jha made their first commit to this issue’s fork.

kristiaanvandeneynde’s picture

Looks good to me now, seems to have a random test failure.

shalini_jha’s picture

Status: Needs work » Needs review
kristiaanvandeneynde’s picture

Status: Needs review » Reviewed & tested by the community

#29 has been addressed, back to RTBC

alexpott’s picture

Version: 11.x-dev » 10.3.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed a9f3b75195 to 11.x and 1122c8d387 to 10.3.x. Thanks!

  • alexpott committed 1122c8d3 on 10.3.x
    Issue #3410098 by andypost, shalini_jha, Akhil Babu, Liam Morland,...

  • alexpott committed a9f3b751 on 11.x
    Issue #3410098 by andypost, shalini_jha, Akhil Babu, Liam Morland,...
andypost’s picture

Thank you! send a patch to follow-up #3415189: Tighten typehint in UserSession::hasPermission() and User::hasPermission()

Please close the MR

Status: Fixed » Closed (fixed)

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