Bug 36149 - userenv stored in plack worker's memory and survive from one request to another
Summary: userenv stored in plack worker's memory and survive from one request to another
Status: Pushed to oldoldoldstable
Alias: None
Product: Koha
Classification: Unclassified
Component: Architecture, internals, and plumbing (show other bugs)
Version: unspecified
Hardware: All All
: P5 - low major
Assignee: Jonathan Druart
QA Contact: Kyle M Hall (khall)
URL:
Keywords:
Depends on:
Blocks: 36367
  Show dependency treegraph
 
Reported: 2024-02-22 09:50 UTC by Jonathan Druart
Modified: 2024-07-25 11:11 UTC (History)
13 users (show)

See Also:
Change sponsored?: ---
Patch complexity: ---
Documentation contact:
Documentation submission:
Text to go in the release notes:
Version(s) released in:
24.05.00,23.11.05,23.05.11,22.11.17,22.05.21
Circulation function:


Attachments
Bug 36149: Unset userenv from middleware (2.39 KB, patch)
2024-03-11 14:24 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove _new_userenv (17.88 KB, patch)
2024-03-11 14:24 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove context stack (5.14 KB, patch)
2024-03-11 14:25 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove dbh_stack (2.47 KB, patch)
2024-03-11 14:25 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove schema_stack (3.72 KB, patch)
2024-03-11 14:25 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove get_schema_cached (675 bytes, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove flush_schema_cached (751 bytes, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Unset userenv from middleware (2.39 KB, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove _new_userenv (17.88 KB, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove context stack (5.14 KB, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove dbh_stack (2.47 KB, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Remove schema_stack (3.72 KB, patch)
2024-03-19 11:39 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Unset userenv from middleware (2.39 KB, patch)
2024-03-20 07:48 UTC, Jonathan Druart
Details | Diff | Splinter Review
Bug 36149: Unset userenv from middleware (3.28 KB, patch)
2024-03-29 18:15 UTC, Nick Clemens (kidclamp)
Details | Diff | Splinter Review
Bug 36149: (follow-up) POD and tidy (934 bytes, patch)
2024-03-29 18:15 UTC, Nick Clemens (kidclamp)
Details | Diff | Splinter Review
Bug 36149: Add userenv middleware to app.psgi (577 bytes, patch)
2024-04-09 12:47 UTC, Julian Maurice
Details | Diff | Splinter Review
Bug 36149: Unset userenv from middleware (3.34 KB, patch)
2024-04-09 17:41 UTC, Kyle M Hall (khall)
Details | Diff | Splinter Review
Bug 36149: (follow-up) POD and tidy (989 bytes, patch)
2024-04-09 17:41 UTC, Kyle M Hall (khall)
Details | Diff | Splinter Review
Bug 36149: Add userenv middleware to app.psgi (634 bytes, patch)
2024-04-09 17:41 UTC, Kyle M Hall (khall)
Details | Diff | Splinter Review

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Druart 2024-02-22 09:50:00 UTC
The userenv is not clear at the beginning of a new request.
If C4::Context->userenv is called before set_userenv we should get undef, not the userenv from the previous request!
Comment 1 David Cook 2024-03-01 00:00:41 UTC
I was scratching my head with bug 34755 and then I realized that this is the reason why. 

If you're doing an OpenID Connect login, and someone else logs into Koha and navigates enough to change the userenv in the worker that you were using before being redirected to the OIDC IdP, you'll get a wrong_csrf_token. Yiiiiiiiikes.
Comment 2 Jonathan Druart 2024-03-11 14:24:55 UTC
Created attachment 163039 [details] [review]
Bug 36149: Unset userenv from middleware

The userenv (logged in user's info) are stored in
$C4::Context->context->{activeuser}, which persists in plack worker's
memory.
It's really bad in theory as we are not cleaning it before or after the
HTTP request, but only when set_userenv is called (what we are doing
commonly in C4::Auth::get_template_and_user).
If C4::Context->userenv is called before set_userenv we should get undef,
not the userenv from the previous request!
In practice this should not be a problem, but well... who really knows?

This patch suggests to have a middleware to deal with removing the
userenv at the beginning of each request (maybe it should be after, right? - FIXME).
Comment 3 Jonathan Druart 2024-03-11 14:24:58 UTC
Created attachment 163040 [details] [review]
Bug 36149: Remove _new_userenv

TODO - better review C4::Auth's changes. Are all the removal of
_new_userenv correct/enough?
Comment 4 Jonathan Druart 2024-03-11 14:25:01 UTC
Created attachment 163041 [details] [review]
Bug 36149: Remove context stack

We are not using it and it's confusing, let's remove the context stack.
Comment 5 Jonathan Druart 2024-03-11 14:25:05 UTC
Created attachment 163042 [details] [review]
Bug 36149: Remove dbh_stack

Same pattern, remove dbh stack
Comment 6 Jonathan Druart 2024-03-11 14:25:08 UTC
Created attachment 163043 [details] [review]
Bug 36149: Remove schema_stack

Same pattern in Koha::Database
Comment 7 Jonathan Druart 2024-03-11 14:26:37 UTC
This is going way too far. The first patch should be enough for this bug report and others moved to their own.

For discussion, do I continue and get support?

Any ideas how to correctly test the first patch?
Comment 8 David Cook 2024-03-11 22:50:11 UTC
(In reply to Jonathan Druart from comment #7)
> This is going way too far. The first patch should be enough for this bug
> report and others moved to their own.

Yeah I think the other patches should be moved to different reports.

> For discussion, do I continue and get support?

I think we do need to fix this one for sure.

> Any ideas how to correctly test the first patch?

Since there is a change to C4::Context::_unset_userenv I think we'd want to make sure that the current usage of that function works correctly.

Otherwise... it's a tough one. We run the unit tests, run some basic manual tests, try things that can do weird things with userenv like the self-checkout. 

We'd want to double-check SIP and other long-running processes to see if they use userenv...

Overall, I suppose it rather break something than leak something, so worthwhile doing in any case.

--

Another thought... what about having C4::Context->userenv use Koha::Cache::Memory::Lite instead of a global variable?

That way we'd have our existing cache flushing take care of this for free. 

I suppose the downside of that would be for things like SIP which flush the cache per-request could have unexpected effects.
Comment 9 Jonathan Druart 2024-03-14 14:45:54 UTC
> Another thought... what about having C4::Context->userenv use
> Koha::Cache::Memory::Lite instead of a global variable?

I've first started with that. But it felt better to have a centralised place where we could add more to deal with the context/env per request.
Comment 10 Jonathan Druart 2024-03-19 11:39:28 UTC
Created attachment 163402 [details] [review]
Bug 36149: Remove get_schema_cached
Comment 11 Jonathan Druart 2024-03-19 11:39:31 UTC
Created attachment 163403 [details] [review]
Bug 36149: Remove flush_schema_cached
Comment 12 Jonathan Druart 2024-03-19 11:39:34 UTC
Created attachment 163404 [details] [review]
Bug 36149: Unset userenv from middleware

The userenv (logged in user's info) are stored in
$C4::Context->context->{activeuser}, which persists in plack worker's
memory.
It's really bad in theory as we are not cleaning it before or after the
HTTP request, but only when set_userenv is called (what we are doing
commonly in C4::Auth::get_template_and_user).
If C4::Context->userenv is called before set_userenv we should get undef,
not the userenv from the previous request!
In practice this should not be a problem, but well... who really knows?

This patch suggests to have a middleware to deal with removing the
userenv at the beginning of each request (maybe it should be after, right? - FIXME).
Comment 13 Jonathan Druart 2024-03-19 11:39:38 UTC
Created attachment 163406 [details] [review]
Bug 36149: Remove _new_userenv

TODO - better review C4::Auth's changes. Are all the removal of
_new_userenv correct/enough?
Comment 14 Jonathan Druart 2024-03-19 11:39:41 UTC
Created attachment 163407 [details] [review]
Bug 36149: Remove context stack

We are not using it and it's confusing, let's remove the context stack.
Comment 15 Jonathan Druart 2024-03-19 11:39:44 UTC
Created attachment 163409 [details] [review]
Bug 36149: Remove dbh_stack

Same pattern, remove dbh stack
Comment 16 Jonathan Druart 2024-03-19 11:39:47 UTC
Created attachment 163412 [details] [review]
Bug 36149: Remove schema_stack

Same pattern in Koha::Database
Comment 17 Martin Renvoize (ashimema) 2024-03-19 12:53:30 UTC
Tests highlight some interesting changes here..

* unset_userenv sets the unserenve to an empty hashref now rather than deleteing/undefining it. (t/db_dependent/Auth.t line 429)
* activeuser is part of the stack system.. we can probably just drop the tests around line 910 in t/db_dependent/Auth.t
* More undef vs empty hashref tests around lines 936 and 943
* undef vs empty string in plugin registers (highlighted by line 57 in t/db_dependent/Koha/Template/Plugin/Registers.t)
* Background jobs tests also failing for the same

I'm generally happy with the approach here.. it simplifies the code a fair bit and I think that's a good thing.  I'm happy to see us go the whole way here personally.. if you've got the appetite to continue Jonathan?
Comment 18 David Cook 2024-03-19 23:08:36 UTC
I still think we're trying to do too much in 1 report. I'd love to see just us clearing the userenv at the start (or end) of the HTTP request, and then backporting that as far back as we can, since that's a bug.

Then the rest can be done as a separate refactoring report which doesn't need to be backported. 

--

On a side note, removing some of the stack stuff will cause conflicts for Bug 20630. That said, we'd need better mechanisms for managing context/userenv and persistent network connections (e.g. DB connection) anyway. 

Outside of a multitenancy scenario, I don't think we'd need the stack stuff at all though.
Comment 19 David Cook 2024-03-19 23:19:00 UTC
(In reply to Jonathan Druart from comment #2)
> This patch suggests to have a middleware to deal with removing the
> userenv at the beginning of each request (maybe it should be after, right? -
> FIXME).

I have a different app where I perform some ORM cleanup at the end of the HTTP request using a Plack middleware, so I'm tempted to do this userenv cleanup at the end of the HTTP request.

But then doing it at the beginning of the request means we might be a bit more confident that we've reset the environment? 

--

I thought that we were flushing the caches at the end of the HTTP request, but looking at debian/templates/plack.psgi, it looks like we actually do that when CGI::new is called (which would be the beginning of most HTTP requests).

At some point, we'll want to move the cache flushes to a Plack middleware as well.
Comment 20 Jonathan Druart 2024-03-20 07:47:48 UTC
(In reply to Martin Renvoize from comment #17)
> I'm generally happy with the approach here.. it simplifies the code a fair
> bit and I think that's a good thing.  I'm happy to see us go the whole way
> here personally.. if you've got the appetite to continue Jonathan?

I will move those patches to a separate bug.


(In reply to David Cook from comment #18)
> On a side note, removing some of the stack stuff will cause conflicts for
> Bug 20630. That said, we'd need better mechanisms for managing
> context/userenv and persistent network connections (e.g. DB connection)
> anyway. 
> 
> Outside of a multitenancy scenario, I don't think we'd need the stack stuff
> at all though.

Yes, must be implemented correctly if we need it back.

(In reply to David Cook from comment #19)
> (In reply to Jonathan Druart from comment #2)
> > This patch suggests to have a middleware to deal with removing the
> > userenv at the beginning of each request (maybe it should be after, right? -
> > FIXME).
> 
> I have a different app where I perform some ORM cleanup at the end of the
> HTTP request using a Plack middleware, so I'm tempted to do this userenv
> cleanup at the end of the HTTP request.
> 
> But then doing it at the beginning of the request means we might be a bit
> more confident that we've reset the environment? 

Yes, agreed, keeping like that then see later if it needs to be tweaked.

> I thought that we were flushing the caches at the end of the HTTP request,
> but looking at debian/templates/plack.psgi, it looks like we actually do
> that when CGI::new is called (which would be the beginning of most HTTP
> requests).
> 
> At some point, we'll want to move the cache flushes to a Plack middleware as
> well.

Yes, what I meant in comment 9 ;)
Comment 21 Jonathan Druart 2024-03-20 07:48:08 UTC
Created attachment 163499 [details] [review]
Bug 36149: Unset userenv from middleware

The userenv (logged in user's info) are stored in
$C4::Context->context->{activeuser}, which persists in plack worker's
memory.
It's really bad in theory as we are not cleaning it before or after the
HTTP request, but only when set_userenv is called (what we are doing
commonly in C4::Auth::get_template_and_user).
If C4::Context->userenv is called before set_userenv we should get undef,
not the userenv from the previous request!
In practice this should not be a problem, but well... who really knows?

This patch suggests to have a middleware to deal with removing the
userenv at the beginning of each request (maybe it should be after, right? - FIXME).
Comment 22 Jonathan Druart 2024-03-20 07:50:42 UTC
(In reply to Jonathan Druart from comment #20)
> (In reply to Martin Renvoize from comment #17)
> > I'm generally happy with the approach here.. it simplifies the code a fair
> > bit and I think that's a good thing.  I'm happy to see us go the whole way
> > here personally.. if you've got the appetite to continue Jonathan?
> 
> I will move those patches to a separate bug.

See bug 36367.
Comment 23 Nick Clemens (kidclamp) 2024-03-29 18:15:08 UTC
Created attachment 164145 [details] [review]
Bug 36149: Unset userenv from middleware

The userenv (logged in user's info) are stored in
$C4::Context->context->{activeuser}, which persists in plack worker's
memory.
It's really bad in theory as we are not cleaning it before or after the
HTTP request, but only when set_userenv is called (what we are doing
commonly in C4::Auth::get_template_and_user).
If C4::Context->userenv is called before set_userenv we should get undef,
not the userenv from the previous request!
In practice this should not be a problem, but well... who really knows?

This patch suggests to have a middleware to deal with removing the
userenv at the beginning of each request (maybe it should be after, right? - FIXME).

To test:
1 - Edit /etc/koha/sites/kohadev/koha-conf.xml to set <plack_workers>1</plack_workers>
2 - Edit about.pl  and add a line after: CGI->new:
    warn Data::Dumper::Dumper( C4::Cointext->userenv() );
3 - tail -f /var/log/koha/kohadev/*.log
4 - View about.pl in staff interface, should get a "somethign's wrong" warning
5 - Reload, you get current user info
6 - Open an incognito tab, sign in as a different user and click some stuff
7 - Reload about.pl in other window
8 - You get the opac user info
9 - Apply patch
10 - Edit /etc/koha/sites/kohadev/plack.psgi and add the middleware after "RealIP":
     enable "+Koha::Middleware::UserEnv";
11 - Restart all
12 - Reload about.pl - you get a "Something's wrong" warning
13 - Click things in opac on incognito window
14 - Reload about.pl  - only "Something's wrong" - you no longer see any user info

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Comment 24 Nick Clemens (kidclamp) 2024-03-29 18:15:11 UTC
Created attachment 164146 [details] [review]
Bug 36149: (follow-up) POD and tidy
Comment 25 Nick Clemens (kidclamp) 2024-03-29 18:17:02 UTC
I faked it for testing, but this would have prevented bugs like bug 35518
It's an easy enough mistake to make (says the guy who made it) so this protection should be beneficial
Comment 26 Marcel de Rooy 2024-04-05 06:40:24 UTC
Could this pattern help in post processing:

sub call {
    my($self, $env) = @_;
    # pre-processing $env
    my $res = $self->app->($env);
 
    return Plack::Util::response_cb($res, sub {
        my $res = shift;
        # do something with $res;
    });
}

Clear userenv in the callback ?
Comment 27 Jonathan Druart 2024-04-05 07:01:56 UTC
(In reply to Marcel de Rooy from comment #26)
> Could this pattern help in post processing:
> 
> sub call {
>     my($self, $env) = @_;
>     # pre-processing $env
>     my $res = $self->app->($env);
>  
>     return Plack::Util::response_cb($res, sub {
>         my $res = shift;
>         # do something with $res;
>     });
> }
> 
> Clear userenv in the callback ?

Yes, but do we really want it to be cleared after? If you do it before you are certain that you are processing the request with a clear env.
Comment 28 Marcel de Rooy 2024-04-05 09:55:52 UTC
(In reply to Jonathan Druart from comment #27)
> Yes, but do we really want it to be cleared after? If you do it before you
> are certain that you are processing the request with a clear env.

And what if we do both :)
Comment 29 Jonathan Druart 2024-04-05 12:04:45 UTC
Could be, if we don't trust ourselves. But IMO only before is needed.
Comment 30 David Cook 2024-04-07 23:52:22 UTC
(In reply to Jonathan Druart from comment #29)
> Could be, if we don't trust ourselves. But IMO only before is needed.

I agree. I think we only need before. Both is probably overkill.
Comment 31 Julian Maurice 2024-04-09 12:44:45 UTC
I think that calling _unset_userenv is not enough. It only deletes $context->{activeuser} and not the corresponding data in $context->{userenv}, so $context->{userenv} continues to hold userenv of all previously logged in users.
C4::Context doesn't seem to have any method to clean the userenv, so maybe _unset_userenv should be modified to do this ?
Comment 32 Julian Maurice 2024-04-09 12:47:26 UTC
Created attachment 164555 [details] [review]
Bug 36149: Add userenv middleware to app.psgi
Comment 33 Kyle M Hall (khall) 2024-04-09 17:41:19 UTC
Created attachment 164567 [details] [review]
Bug 36149: Unset userenv from middleware

The userenv (logged in user's info) are stored in
$C4::Context->context->{activeuser}, which persists in plack worker's
memory.
It's really bad in theory as we are not cleaning it before or after the
HTTP request, but only when set_userenv is called (what we are doing
commonly in C4::Auth::get_template_and_user).
If C4::Context->userenv is called before set_userenv we should get undef,
not the userenv from the previous request!
In practice this should not be a problem, but well... who really knows?

This patch suggests to have a middleware to deal with removing the
userenv at the beginning of each request (maybe it should be after, right? - FIXME).

To test:
1 - Edit /etc/koha/sites/kohadev/koha-conf.xml to set <plack_workers>1</plack_workers>
2 - Edit about.pl  and add a line after: CGI->new:
    warn Data::Dumper::Dumper( C4::Cointext->userenv() );
3 - tail -f /var/log/koha/kohadev/*.log
4 - View about.pl in staff interface, should get a "somethign's wrong" warning
5 - Reload, you get current user info
6 - Open an incognito tab, sign in as a different user and click some stuff
7 - Reload about.pl in other window
8 - You get the opac user info
9 - Apply patch
10 - Edit /etc/koha/sites/kohadev/plack.psgi and add the middleware after "RealIP":
     enable "+Koha::Middleware::UserEnv";
11 - Restart all
12 - Reload about.pl - you get a "Something's wrong" warning
13 - Click things in opac on incognito window
14 - Reload about.pl  - only "Something's wrong" - you no longer see any user info

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Comment 34 Kyle M Hall (khall) 2024-04-09 17:41:25 UTC
Created attachment 164568 [details] [review]
Bug 36149: (follow-up) POD and tidy

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Comment 35 Kyle M Hall (khall) 2024-04-09 17:41:28 UTC
Created attachment 164569 [details] [review]
Bug 36149: Add userenv middleware to app.psgi

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Comment 36 Martin Renvoize (ashimema) 2024-04-09 22:36:19 UTC
(In reply to Julian Maurice from comment #31)
> I think that calling _unset_userenv is not enough. It only deletes
> $context->{activeuser} and not the corresponding data in
> $context->{userenv}, so $context->{userenv} continues to hold userenv of all
> previously logged in users.
> C4::Context doesn't seem to have any method to clean the userenv, so maybe
> _unset_userenv should be modified to do this ?

We've gone PQA now here.. is Julian's comment not valid as I don't see any mebtion of it for change to the code in the subsequent QA process?
Comment 37 David Cook 2024-04-09 23:22:41 UTC
(In reply to Martin Renvoize from comment #36)
> (In reply to Julian Maurice from comment #31)
> > I think that calling _unset_userenv is not enough. It only deletes
> > $context->{activeuser} and not the corresponding data in
> > $context->{userenv}, so $context->{userenv} continues to hold userenv of all
> > previously logged in users.
> > C4::Context doesn't seem to have any method to clean the userenv, so maybe
> > _unset_userenv should be modified to do this ?
> 
> We've gone PQA now here.. is Julian's comment not valid as I don't see any
> mebtion of it for change to the code in the subsequent QA process?

Julian makes an interesting point, although I don't think it's a blocker here, and we can proceed with the PQA as is.

In Bug 36367, Jonathan has a patch that undefs the whole of $context->{userenv} in C4::Context::unset_userenv, so I think that should suffice as a follow-up.
Comment 38 Jonathan Druart 2024-04-16 07:33:28 UTC
Yes, I first submitted a version with a full removal but I have been asked to provide a small bugfix here and move the cleaning part to a separate bug (see bug 36367).

Please test and QA it :)
Comment 39 Julian Maurice 2024-04-16 07:46:08 UTC
(In reply to David Cook from comment #37)
> Julian makes an interesting point, although I don't think it's a blocker
> here, and we can proceed with the PQA as is.
Yes, not a blocker.
Comment 40 Wainui Witika-Park 2024-04-24 02:15:45 UTC
Applied to 22.05
Comment 41 Frédéric Demians 2024-04-24 11:01:47 UTC
Backported to 22.11
Comment 42 Tomás Cohen Arazi (tcohen) 2024-05-15 20:52:30 UTC
Pushed for 24.05!

Well done everyone, thank you!