Problem/Motivation
When someone masquerading as other user, the last user entity got changes in last access time (by core's user_last_access_subscriber service)
To prevent changing user entity it needs to decorate this service
Issue we have on D7 we also have on D8.
https://www.drupal.org/project/masquerade/issues/2921097
Proposed resolution
- introduce configuration to manage behavior - masquerade.settings configuration's key update_user_last_access to TRUE and post update hook for existing sites
- decorate user_last_access_subscriber service to prevent updates
- decorate session_manager.metadata_bag service to prevent "session is started" checks, see comments #23 and #24
Remaining tasks
- review and do testing with other contrib modules
- commit
User interface changes
no
API changes
- Added \Drupal\masquerade\Session\MetadataBag with setMasquerade, getMasquerade, cleanMasquerade methods accessible from session->getMetadata() object
- Added configuration with update hoot to preserve existing behavior
Data model changes
Session flag now wrapped into own session bag with useful methods
Release notes snippet
Masqueraded user's last access time no longer updated by default
| Comment | File | Size | Author |
|---|---|---|---|
| #56 | 3042321_56.patch | 11.56 KB | mkalkbrenner |
| #51 | 3042321_51.patch | 11.98 KB | mkalkbrenner |
| #49 | 3042321_49.patch | 11.69 KB | jan-e |
| #45 | 3042321_45.patch | 11.7 KB | mkalkbrenner |
| #43 | 3042321-43.patch | 11.47 KB | mkalkbrenner |
Comments
Comment #2
xsdx commentedProviding patch.
Comment #3
xsdx commentedComment #4
Ivica Arbanas commentedVerified. It works!
Thanks
Comment #5
Ivica Arbanas commentedReviewed and tested. It works!
Thanks
Comment #6
andypostGhanks for the patch, this addition require tests and steps to reproduce, also code needs a bot of cleanup
Comment #7
xsdx commented@andypost I'm not sure what you mean by code cleanup. I've checked code with PHPCS Drupal standard with Drupal coder and no issues there. Code consists of minimum code for this to work.
Steps for reproduce are:
1. Masquerade as any user
2. Last access timestamp should not change
Currently it changes because core user module triggers on onKernelTerminate mathod update to this timestamp in db.
So what this patch is doing is overriding this method and updating it only in case of Masquerade as user.
As for tests I agree. We should have them
Comment #8
megachrizI would note here which definitions are altered and why.
I'm not sure if using
@inheritdocand a describing text may be used together. I remember that I've read somewhere you should use one or the other.Anyway, I believe the
@inheritdocshould always be defined within curly brackets:{@inheritdoc}Same. Not sure if
{@inheritdoc}should be used here if the method already has a description.Comment #9
shubham.prakash commentedSince
{@inheritdoc}is required, extra comment has been removed.Comment #10
jedihe commentedWorking on adding a test for this.
Comment #11
jedihe commentedJust added an assert for this, in MasqueradeTest.php.
Getting the service provider to actually register in the test proved challenging, that problem was caused by the new event subscriber not being declared in masquerade.services.yml (hint: checking core/modules/system/tests/modules/service_provider_test was very helpful); the full patch includes that. Also, using $account->getLastAccessedTime() was always returning 0, so I had to fetch the value directly from users_field_data.
Let's see if the testbot likes this...
Comment #12
jedihe commentedAlright! the test works.
Comment #13
andypostnot sure session should be red from global, there's a request object with session inside passed via event object
PS: https://github.com/symfony/symfony/issues/10557
could use
MasqueradeUserRequestSubscriber::classsyntax to explicitly define usageComment #14
jedihe commentedThx for reviewing @andypost! here's the improved patch.
Comment #15
andypostMaybe allow to configure it?
Comment #16
jedihe commentedSure! would a simple checkbox do it? I'm thinking something like "Prevent changing last access" with description "Prevents modifying the last access timestamp for an account, when masquerading as that user".
As for implementation, I'm not sure it's possible to read config from the service provider alter() call; if that's the case, the next idea I have is to just go ahead with the override, but check for config in MasqueradeUserRequestSubscriber itself.
Comment #17
andypostshould use service
should be configurable and use `MasqueradeUserRequestSubscriber::class` syntax
Comment #18
jedihe commented@andypost: #14 already fixes #17.1 and #17.2.b. As for #17.2.a, can you please have a look at #16? I just want to be sure my approach is sound before I put more work into it :).
Thanks!
Comment #19
andypostHey! The example of it is core"s configurable language manager so it's doable at least)
On other hand I prefer to keep default behaviour and get opinions from distributions and GDPR POV(
Tl'dr opt-in vs opt-out
Comment #20
scott_euser commentedI suppose the GDPR would be a wider issue if that was a concern? Eg, an opt-in on a user profile / registration with something like "Allow administrators to masquerade as me in order to support me", but that would be out of scope of this issue.
I personally cannot think of a case where a site builder would have an issue where masquerading no longer changes the last accessed timestamp on their users.
Comment #21
andypostStill no UI and GDPR could be a reason to change port update hook, any way needs review
Comment #22
andypostthis affects upgrade path, probably safer to keep previous behavior for already installed sites
Comment #23
andypostJust debuged this:
- session reports that it's not started! (that's why this check in isMasquerading() method)
- this call to has() throws warning for every page because of previous
Comment #24
andypostLooks this way it works fine, needs test for decorators
I gonna add this to next beta #2982514: Masquerade 8.x-2.1 stable release plan
Comment #25
andypostAdded basic kernel test for service ovverrides and a bit of cleanup
The key should remain "masquerading" to stay compatible with previous sessions
Comment #26
andypostFix typo
Comment #27
andypostUse to load user entity to be sure it is not cached in test runner
Comment #28
andypostAdded change record https://www.drupal.org/node/3108941 (would be great to update it with details about decorations)
Fix CS issue in last patch
Comment #29
andypostupdated summary
Comment #30
claudiu.cristeaThis would be a very good fix. Few remarks:
setMasquerade()sounds like we set only the @masquerade service. Either create anothersetConfigFactory()or rename tosetServices()(orinjectServices()).Why casting to
(bool), shouldn't that work out-of-the-box with our config system?Also, if
!$this->masquerade->isMasquerading()is TRUE we don't need to compute$forceanymore. So, probably, something like:...would be better.
I would also rename
$forceto$update_user_last_accessto be consistent with the config key.I'm not sure I get why we need this decorator. Could you, please, create a regression test for #23 so we can prove how this decorator is solving the problem?
This tests the default setting (FALSE). Let's extend and test also with
update_user_last_access: trues/public/protected
Could we replace the 3 lines with: $this->assertInstanceOf()?
s/assertIdentical/assertSame
Same, I think assertInstanceOf() is more appropriate.
Comment #31
andypostThe core issue may help to move override flag
Comment #32
andypostneeds polishing after https://www.drupal.org/node/3109877 and may require 8.9 core next release
Comment #33
eli-tRerolled patch in #28 against current HEAD of 8.x-2.x.
This intentionally has not addressed the feedback in #30 and #32 at this point.
Setting to Needs Review anyway to kick off tests.
Comment #34
eli-tRunning drush cr on Drupal 9.1.5 after installing the patch in #33 gives the following warning:
[warning] Declaration of Drupal\masquerade\EventSubscriber\MasqueradeUserRequestSubscriber::onKernelTerminate(Symfony\Component\HttpKernel\Event\PostResponseEvent $event) should be compatible with Drupal\user\EventSubscriber\UserRequestSubscriber::onKernelTerminate(Symfony\Component\HttpKernel\Event\TerminateEvent $event) MasqueradeUserRequestSubscriber.php:16This also causes the test failures in https://www.drupal.org/pift-ci-job/2000260
Comment #35
eli-tComment #36
eli-tComment #38
eli-tThe patch in #28 adds a class MasqueradeUserRequestSubscriber which extends Drupal\user\EventSubscriber\UserRequestSubscriber
This class is not covered by Drupal's BC policy: https://www.drupal.org/about/core/policies/core-change-policies/drupal-8...
In Drupal 9, the method signature for UserRequestSubscriber::onKernelTerminate() has changed, replacing the PostResponseEvent with a KernelEvent, in line with the former being deprecated since Symfony 4.3.
So as it stands I'm not sure how to make this patch compatible with both Drupal 8 and Drupal 9 without some kind of shim.
Comment #39
tobiberlinAs we make use of the masquerade module in order to support users of our patform we would really appreaciate this functionality to be able to see if an user really did something on our platform on his own. I did not test the patch yet - before I dig in deeper I'd like to know if there are any plans for a new release of this module which may only be compatible with Drupal 9 to solve the problem mentioned above bei ELI-T?!
Comment #40
jan-e commentedThe patch in #36 just works fine for Drupal 9.4, after changing ‘true’ to ‘false’ in masquerade.settings.yml. I would not be too worried about breaking backwards compatibility with Drupal 8. And possible future BC breaks might happen, so that is something to test once in a while.
Comment #41
eli-tAgreed, now Drupal 8 is no longer supported, we no longer need a fix that works for 8 and 9.
Comment #42
jan-e commentedRTBC +1
Comment #43
mkalkbrennerPatch #36 doesn't apply to the 8.x-2.x branch anymore. Here's an adjusted version without any functional changes.
Comment #44
w01f commentedPatch looks good after running db update on latest 10.0.9!
Comment #45
mkalkbrennerAdjusted patch for rc3
Comment #47
jan-e commentedAren't you mixing up
$this->authUserand$this->auth_userin Functional/MasqueradeTest.php?$this->auth_useris undefined in the first line offunction testMasquerade().Comment #48
mkalkbrennerMight be. I didn't care about the tests and just adjusted the existing patches here to by able to be applied against the latest versions.
Comment #49
jan-e commentedThanks for adjusting the patch for masquerade 8.x-2.0-rc3. Let us see what the attached patch does in the tests.
Comment #50
jan-e commentedWell. 2 failing tests fixed. A bit better.
Comment #51
mkalkbrennerI took a quick look at the failing tests.
Comment #52
mkalkbrennerComment #53
jan-e commentedRTBC +1
Comment #54
mkalkbrenner@Jan-E you can set the issue status to RTBC.
Comment #55
jan-e commentedComment #56
mkalkbrennerThe last patch erroneously modified the info.yml
Comment #58
andypostThank you! Pushed to -dev version as rc4 bugfix just rolled out
Comment #59
andypostMissed one coding standards message but fine
Comment #60
jan-e commentedFor the record: #56 applies without problems to masquerade 8.x-2.0-rc4.
Comment #62
solideogloria commentedShould a new issue be opened for adding a configuration form for updating this setting? It's not a big need for me, as I can set the config value. But others might not be able to do that.
Comment #63
andypostI think it needs some readme update as it will be confusing if masquerade will update last accessed
Comment #64
brad.bulger commentedThere needs to be at least an item in the README file and preferably a config form.