Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle session closure properly for redirecting to a controller in a post_login hook #1303

Closed
GitHubUser4234 opened this issue Sep 7, 2016 · 23 comments · Fixed by #2144
Closed
Assignees
Labels

Comments

@GitHubUser4234
Copy link
Contributor

GitHubUser4234 commented Sep 7, 2016

When a redirect to a controller is performed within the method of a post_login hook, an internal error occurs and gets printed in the webserver log (not NC log):

PHP Fatal error:  
Uncaught exception 'Exception' with message 'Session has been closed - no further changes to the session are allowed' in /server/lib/private/Session/Internal.php:154
Stack trace:
#0 /server/lib/private/Session/Internal.php(64): OC\\Session\\Internal->validateSession()
#1 /server/lib/private/Session/CryptoSessionData.php(164): OC\\Session\\Internal->set('encrypted_sessi...', 'e08a3041c452d86...')
#2 /server/lib/private/Session/CryptoSessionData.php(67): OC\\Session\\CryptoSessionData->close()
#3 [internal function]: OC\\Session\\CryptoSessionData->__destruct()
#4 {main}
  thrown in /server/lib/private/Session/Internal.php on line 154

Here is an example code of this happening:

Redirect in the method of a post_login hook
Target method of the controller

The problem is caused by the CryptoSessionData trying to close a session that is already closed. Even if the example code didn't include any session related code, the error would still occur (this has been tested).

The issue has been discussed with @LukasReschke with the result that further investigation would be necessary on whether session closure is actually necessary in this situation and if yes, how to handle session closure properly.

PR #1023 depends on this, any help is appreciated, thanks 😃

Edit: A subsequent call to the next method within the controller requiring CSRF fails saying "CSRF check failed", even though a request token was posted to the server correctly. Probably the token got lost somehow because for this call an attempt to close the session is made yet again, resulting in the same stacktrace as above. So it looks like not trying to close the session would be of a help?

@GitHubUser4234
Copy link
Contributor Author

Not sure whether it is of any help, by coincidence I saw that the recently reported #1282 has the same stacktrace, but in a different testing scenario. Maybe there is some correlation? If yes, one fix could close two issues 😋

@nickvergessen
Copy link
Member

@GitHubUser4234 I ran into a similar issue latly, so please retry on master, whether 2cd92d0 fixes the issue

@GitHubUser4234
Copy link
Contributor Author

GitHubUser4234 commented Nov 10, 2016

@nickvergessen : Thanks for the hint, I just retried, but unfortunately the error is still there. Line numbers of the stacktrace remain unchanged.

@GitHubUser4234
Copy link
Contributor Author

GitHubUser4234 commented Nov 11, 2016

As discussed with @nickvergessen in IRC, this can quickly be reproduced by adding the following lines to

:

header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
exit();

The error would then occur in the server log (NOT nc log), for instance on Apache in the error_log / ssl_error_log file.

@tcitworld
Copy link
Member

Ran into the same issue while trying to have #1893 in a separate app.

@tcitworld
Copy link
Member

More informations before the session issue itself happens. The default encryption module app is enabled but not used.

[Mon Nov 14 18:58:12 2016] User "tcit" removed from group "admin"
[Mon Nov 14 18:58:12 2016] unlink(/home/tcit/dev/server/data/tcit/files_encryption/OC_DEFAULT_MODULE/tcit.privateKey): Permission denied at /home/tcit/dev/server/lib/private/legacy/helper.php#215
[Mon Nov 14 18:58:12 2016] unlink(/home/tcit/dev/server/data/tcit/files_encryption/OC_DEFAULT_MODULE/tcit.publicKey): Permission denied at /home/tcit/dev/server/lib/private/legacy/helper.php#215
[Mon Nov 14 18:58:12 2016] rmdir(/home/tcit/dev/server/data/tcit/files_encryption/OC_DEFAULT_MODULE): Permission denied at /home/tcit/dev/server/lib/private/legacy/helper.php#213
[Mon Nov 14 18:58:12 2016] rmdir(/home/tcit/dev/server/data/tcit/files_encryption): Directory not empty at /home/tcit/dev/server/lib/private/legacy/helper.php#213
[Mon Nov 14 18:58:12 2016] rmdir(/home/tcit/dev/server/data/tcit): Directory not empty at /home/tcit/dev/server/lib/private/legacy/helper.php#219
[Mon Nov 14 18:58:12 2016] User deleted: "tcit"
[Mon Nov 14 18:58:12 2016] unlink(/home/tcit/dev/server/data/tcit/files_encryption/OC_DEFAULT_MODULE/tcit.publicKey): Permission denied at /home/tcit/dev/server/lib/private/Files/Storage/Local.php#230
[Mon Nov 14 18:58:12 2016] Logout occurred
[Mon Nov 14 18:58:12 2016] session_regenerate_id(): Cannot regenerate session id - session is not active at /home/tcit/dev/server/lib/private/Session/Internal.php#115

@MorrisJobke MorrisJobke mentioned this issue Nov 15, 2016
47 tasks
@GitHubUser4234
Copy link
Contributor Author

Ran into the same issue while trying to have #1893 in a separate app.

Exact the same stacktrace as in my first post appears in your logs? And also a similar situation (post_login hook -> Controller)?

@MorrisJobke
Copy link
Member

@LukasReschke and @nickvergessen want to look into this again for Nextcloud 11

@MorrisJobke MorrisJobke added this to the Nextcloud 11.0 milestone Nov 15, 2016
@tcitworld
Copy link
Member

Exact the same stacktrace as in my first post appears in your logs?

Yes.

And also a similar situation (post_login hook -> Controller)?

No, trying to delete an user and disconnect him.

@GitHubUser4234
Copy link
Contributor Author

@LukasReschke and @nickvergessen want to look into this again for Nextcloud 11

Very happy, thanks guys :)

@GitHubUser4234
Copy link
Contributor Author

Exact the same stacktrace as in my first post appears in your logs?

Yes.

And also a similar situation (post_login hook -> Controller)?

No, trying to delete an user and disconnect him.

Interesting information, so seems the problem might have a wider impact, hm...

LukasReschke added a commit that referenced this issue Nov 15, 2016
Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
@LukasReschke
Copy link
Member

Minimal example is in the branch minimal-example-for-1303. See 0191995

To test this try to login and look at /var/log/apache2/error.log:

[Tue Nov 15 12:51:59.122300 2016] [:error] [pid 3689] [client 10.211.55.2:61533] PHP Fatal error:  Uncaught Exception: Session has been closed - no further changes to the session are allowed in /media/psf/stable9/lib/private/Session/Internal.php:154\nStack trace:\n#0 /media/psf/stable9/lib/private/Session/Internal.php(64): OC\\Session\\Internal->validateSession()\n#1 /media/psf/stable9/lib/private/Session/CryptoSessionData.php(164): OC\\Session\\Internal->set('encrypted_sessi...', '2189243c78b2480...')\n#2 /media/psf/stable9/lib/private/Session/CryptoSessionData.php(67): OC\\Session\\CryptoSessionData->close()\n#3 [internal function]: OC\\Session\\CryptoSessionData->__destruct()\n#4 {main}\n  thrown in /media/psf/stable9/lib/private/Session/Internal.php on line 154

cc @rullzer

rullzer added a commit that referenced this issue Nov 15, 2016
If the session is cleared and closed for whatever reason the loadVersion
will write to the session anyways. This will lead to an exception.

This should fix #1303

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
@MorrisJobke
Copy link
Member

@GitHubUser4234 🙌

@GitHubUser4234
Copy link
Contributor Author

Thanks a lot @MorrisJobke @nickvergessen @LukasReschke @rullzer for the fix :))

The fix solves the major part of the problem, however a flaw has been found which I'm currently discussing with @LukasReschke :

Remove @NoCSRFRequired from thetryLogin() method in the LoginController and then run the minimal-example-for-1303 (see above): The first time when clicking the login button AFTER the post_login hook was called, CSRF fails. However when clicking the browser's back button and trying it again, the error doesn't occur again.

@GitHubUser4234
Copy link
Contributor Author

GitHubUser4234 commented Nov 16, 2016

A reminder for everyone still running into the same problem even after applying the fix: In case the methods involved work with sessions, you also need add the "@usesession" annotation for them.

@rullzer
Copy link
Member

rullzer commented Nov 17, 2016

Mmmm @GitHubUser4234 I think this is because we do write a requesttoken into the session. Then the second time we want to compare that but it fails hard. I will discuss with @LukasReschke and see if we can fix this.

@LukasReschke LukasReschke reopened this Nov 17, 2016
@GitHubUser4234
Copy link
Contributor Author

Mmmm @GitHubUser4234 I think this is because we do write a requesttoken into the session. Then the second time we want to compare that but it fails hard. I will discuss with @LukasReschke and see if we can fix this.

Awesome :))

@rullzer
Copy link
Member

rullzer commented Nov 24, 2016

As discussed today on IRC. Lets try to solve this somewhat safe early in the 12 cycle.

@jospoortvliet
Copy link
Member

'early' would be now, I suppose :D

@GitHubUser4234
Copy link
Contributor Author

GitHubUser4234 commented Feb 28, 2017

'early' would be now, I suppose :D

Hehe, yeah would be really great if someone could have a look at it :)

@GitHubUser4234
Copy link
Contributor Author

@rullzer Hem, hem :)

@rullzer
Copy link
Member

rullzer commented Mar 13, 2017

Ah yes. sorry this slipped off my radar. No promises but I have it on the list for this week... Now we just pray nothing comes up

rullzer pushed a commit that referenced this issue Mar 13, 2017
Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
rullzer added a commit that referenced this issue Mar 13, 2017
This is a hacky way to allow the use case of #1303.

What happens is

1. User tries to login
2. PreLoginHook kicks in and figures out that the user need to change
their LDAP password or whatever => redirects user
3. While loading the redirect some logic of ours kicks in and logouts
the user (thus clearing the session).
4. We render the new page but now the session and the page disagree
about the CSRF token

This is kind of hacky but I don't think it introduces new attack
vectors.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
rullzer added a commit that referenced this issue Mar 30, 2017
Do not clear CSRF token on logout (fix for #1303)
@GitHubUser4234
Copy link
Contributor Author

Cool, it has been merged, thanks a lot!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants