Updated: Comment #N

Problem/Motivation

There are multiple issues like #2057607: The request does not contain the _account on exception pages (403/404) and many more which shows that we can't deal with just the request object anymore
but have to copy the _account object all the time from the "parent" request.

Proposed resolution

Create a current user service, which just has the account stored in there magically, so no method call will be needed.

Remaining tasks

#2062265: _account is not available in Request in _block_get_renderable_region()
#2062269: _account is not available in Request in during any UnitTest
update change notice https://drupal.org/node/2068221

API changes

Instead of using $request->attributes->get('_account') you can just use Durpal::currentUser() or inject the 'current_user' service, which is an account interface object.

#2061899: Remove references to global $user in Comment module
#2062091: Remove references to global $user in Block module Assigned to: m1r1k
#2062097: Remove calls to deprecated global $user in theme.inc
#2061907: Remove calls to deprecated global $user in shortcut module

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

One potential solution would be to proxy the access to the _account object through a service which is request aware.

Once the _account is set on the request, use it, otherwise ask AuthenticationManager to do so.

dawehner’s picture

Just as a reference here is the way how symfony handles it: http://symfony.com/doc/current/book/security.html#where-do-users-come-fr... . In our world this would be a method on the authentication manager directly.

m1r1k’s picture

Issue summary: View changes

Add Remaining tasks that have same problem and related issues

dawehner’s picture

Status: Active » Needs review
FileSize
2.16 KB

Here is a patch which introduces a current user service.

larowlan’s picture

Awesome!

@@ -0,0 +1,65 @@
+} ¶

Trailing space, needs newline (nitpick)

Should we convert one of the problematic ones listed in the related issues above to demonstrate it works?
Should we add a unit test?

dawehner’s picture

Issue tags: +PHPUnit
FileSize
4.45 KB

This time this actually works and has a test.

larowlan’s picture

@@ -0,0 +1,65 @@
+} ¶

still persists (nitpick)

but looks good otherwise

larowlan’s picture

Issue summary: View changes

Add related issue

larowlan’s picture

Title: Figure out how to ensure that _account is always available. » Create a current user service to ensure that current account is always available

New title and updated issue summary

dawehner’s picture

FileSize
555 bytes
4.52 KB

Also added a bit of documentation.

webchick’s picture

Priority: Normal » Critical
Issue tags: +API change, +Approved API change

This blocks a critical (#2040065: Remove _account from request and use the current user service instead.), so it's critical.

It's also approved by catch and I. Tagging.

andypost’s picture

agree with #4 - one of problematic issues should be used to demo the introduced concept

andypost’s picture

Issue summary: View changes

Updated issue summary.

dawehner’s picture

FileSize
2.27 KB
6.79 KB

I have chosen the block one, as it has the smallest amount of code.

catch’s picture

Should this also remove _account from the request object or is that a follow-up?

Crell’s picture

Why are we removing _account from the request at all?

catch’s picture

Why have it there if there's a service handling it?

andypost’s picture

The approach is nice but require to inject the service into all controllers that accept request as well so probably better:
1) leave _account in global request object
2) when no _account in request use \Drupal::account()

anyway this breaks encapsulation or require to inject service to all controllers

catch’s picture

I don't see a problem with injecting this into controllers that need it.

tim.plunkett’s picture

Right now, any controller can just put Request $request in their method and it is automatically passed to them. That's a really nice feature.

catch’s picture

Request is automatically passed, _account gets lost all over the place like #2040065: Remove _account from request and use the current user service instead. so you either have to explicitly set it whenever creating a request or can't rely on it being there anyway.

Also the way _account is accessed from request is really, really ugly.

dawehner’s picture

Me neither. Does that mean that we would have to convert every instance in this issue?

catch’s picture

Another reason we should remove _account: https://drupal.org/node/2036351#comment-7752121

@dawehner - we either need to do it here, or open another critical follow-up. I'm not too fussed either way but since there's disagreement on doing it at all, I think we should probably make the final decision here regardless - I don't want to have the same conversation twice about the same thing once immediately after the other.

dawehner’s picture

I absolutely agree that we should stop the _account conversions based upon this issue.

When converting I would suggest to do just $request->attributes->get(_account) => Drupal::account() or now, or should we also inject things? This would make the patch way bigger.

Damien Tournoud’s picture

The CurrentAccount service introduced in this patch (registered as current_account) is very close to Symfony SecurityContext service, usually registered at security.context.

This brings us one step further in our piece-by-piece reimplementation of Symfony's security component. Is it time to stop and just leverage the component that exists?

Crell’s picture

Damien: I am not going to burn any karma on that drastic of an API change at this stage of the game. Our authorization system is also, as I understand it, very different than Symfony's so it's not like we could just drop it in without a lot of work.

Damien Tournoud’s picture

Crell: I did the research, and described what need to happen. It's clearly less complicated than rebuilding the whole thing from scratch, piece by piece. But of course, it's also fine to ship Drupal 8 with an half-backed API that nobody will want to touch with a ten-foot pole.

dawehner’s picture

Are there more issues which are not solvable by without changing APIs on the authentication system?
We not only maybe have bugs, but we also have a limited amount of people/time.

andypost’s picture

#22 makes sense because we already have bits of this invented here. Symfony have great doc about security so Drupal is implementing same code step-by-step...

Initially in #335411: Switch to Symfony2-based session handling was proposed to use SessionProxy then context approach #1260864: Convert global $user to a context key was wont-fixed by Crell and finally #1858196: [meta] Leverage Symfony Session components we have 40k patch that passes tests and implements listener on request|response and uses global $user object.

#1890878: Add modular authentication system, including Http Basic; deprecate global $user implements route enhancer to home-grown authentication system very similar to symfony's

As masquerade module maintainer I'd like to have swappable service but I think domain module will bring more questions.

@dawehner suppose more bugs will be filed when contrib will start porting to 8.x, all issues about _account are filed within One week as result of 1 day testing d7 upgrade and 1 day code sprint on issues #2047951: [META] Remove calls to deprecated global $user and $GLOBALS['user'] and #2048171: [meta] Replace user_access() calls with $account->hasPermission() wherever possible.

Suppose at the current release phase better to investigate all known issues and available implementations

msonnabaum’s picture

#11 looks ok to me. I don't see why we'd try to expand the scope here beyond that. We just need a simple service that returns the current user.

Even if we ended up using symfony's security component in d9 I'd still keep this interface and delegate so that people didnt have to call ->getToken()->getUser().

dawehner’s picture

FileSize
2.82 KB

We talked a bit in IRC about it, so we will automatically generate a AccountInterface object in the service container using the authentication manager as factory.

Even there was a beer lost on this patch ...

dawehner’s picture

Issue summary: View changes

Added related issue.

tim.plunkett’s picture

One of the nice things about it being on the request is that when we use the controller resolver, a controller can always get the request passed to it, with no need for our static factory injection pattern.

This is really common for forms.

This will mean that a lot of forms will now need to get this service, and switch to needing full injection...

tim.plunkett’s picture

My last comment becomes almost obsolete if #2059245: Add a FormBase class containing useful methods goes in.

Damien Tournoud’s picture

I agree that getting the current account from the request is what you would expect... but Symfony's Request object is very inextensible, and the only API that we can use for that is the current ugly, non-semantic and error-prone:

$request->attributes->get('_account');

The only way to do that right now would be to sub-class the Request object. I'm not sure I would recommend that.

dawehner’s picture

FileSize
681 bytes
3.49 KB

Let's also add a method to the ControllerBase as talked in IRC.

JohnAlbin’s picture

$request->attributes->get('_account'); is procedural code with a dead-OO pelt draped over it.

JohnAlbin’s picture

Issue summary: View changes

blub

Crell’s picture

@@ -597,6 +597,12 @@ services:
+  current_user:
+    class: Drupal\Core\Session\AccountInterface
+    factory_method: authenticate
+    factory_service: authentication
+    arguments: ['@request']
+    scope: request

I want to have a test to verify that this does work cleanly through a subrequest properly. It should, but I want to be extra careful here. If we can test that it stacks properly then I am OK with committing this approach.

dawehner’s picture

FileSize
6.67 KB
10.16 KB

There we go.

Crell’s picture

@@ -94,7 +94,7 @@ public function testControllerPlaceholdersDefaultValues() {
-  public function testControllerPlaceholdersDefaultValuesProvided() {
+  public function ptestControllerPlaceholdersDefaultValuesProvided() {

Was this supposed to be in the patch? (A lot of test methods have it now.)

@@ -7,10 +7,37 @@
+  public function __construct(HttpKernelInterface $http_kernel) {
+    // TODO: Implement __construct() method.
+    $this->httpKernel = $http_kernel;
+  }

This TODO seems TODONE. :-)

dawehner’s picture

FileSize
4 KB
7.08 KB

Ups.

Crell’s picture

Much better. :-) I don't see how the test works, though. It's not changing the user that I can see, is it?

msonnabaum’s picture

#37 looks great.

dawehner’s picture

Do you mean something like this?

dawehner’s picture

Crell’s picture

Status: Needs review » Reviewed & tested by the community

OK, let's do this thing.

catch’s picture

Title: Create a current user service to ensure that current account is always available » Change notice: Create a current user service to ensure that current account is always available
Status: Reviewed & tested by the community » Active
Issue tags: +Needs change record
dawehner’s picture

Some of the changed change-records:

https://drupal.org/node/2049309
https://drupal.org/node/2032447
https://drupal.org/node/2017231

Should there we another one, or does 2) actually describes enough?

chx’s picture

Title: Change notice: Create a current user service to ensure that current account is always available » Create a current user service to ensure that current account is always available
Status: Active » Fixed
Issue tags: -Needs change record

2) is enough.

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

Anonymous’s picture