-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Improve session cookie handling #39916
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
Conversation
|
Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would create a changelog item based on your changes. |
|
It was a setup issue. The "heartbeat" endpoint must be out of the shibboleth auth scope, same as with it was for the "status.php", public sharing, and other endpoints. |
|
Remarks:
|
|
|
For oauth2, at least for the web UI it doesn't seem to be relevant. The web UI will still use the cookie, so it falls into the usual use case. For the case of the new web frontend, it works although the requests are a bit odd. The web frontend is using the bearer token, and it seems that even if the cookie expires, the bearer token kicks in, so the requests go through. |
Just to clarify things: we're dealing with 2 different cookies. The cookie containing the session id, which doesn't expire (or expires with the session), and the cookie containing the passphrase to decrypt the contents of the session, which now expires. From the user's perspective, yes, the session is extended when the user logs in. |
The oc_sessionPassphrase cookie will always be sent for all the non-ajax requests in order to update the expiration time accordingly. The expiration time will match the one set in the 'session_lifetime' configuration in config.php. If the 'session_lifetime' isn't set, the expiration for the cookie will be set to "session" time. If the 'session_keepalive' isn't set as false, a periodic "heartbeat" request will be performed to prevent the browser session from being expired. The "/heartbeat" will always update the expiration time for the oc_sessionPassphrase cookie. Login out will cause the cookie to be deleted.
19dbfb6 to
82983a9
Compare
|
rebased |
|
I don't think we can improve the quality for sonarcloud in this case:
|
|
https://cloud.owncloud.com/index.php/s/U5MnLdl4VB82V4D Installed a 10.9.1 and the PR and I did not get logged out. Only installed OAuth2 and 2FA as apps, and run the updates on the marketplace. No logout after the defined time Enabled Apps: for some reason OAuth2 is listed twice. |
|
opened a ticket for the duplicate app #39930 |
|
@voroyam Could you test with higher timeouts? i.e 120 or 180 secs? Very low timeouts might not be possible due to variouse things (notification etc.) |
|
Sure |
tested with 180s same result. no logout. |
|
@jvillafanez Not sure if this works as expected as the heartbeat always extends the session. Are we doing something wrong? |
That's intended. The heartbeat should always extend the session. You can set the Note that this will only affect the cookie. For the case of oAuth2, it's expected that the client will always send a bearer token in the authentication header. The handling for the bearer token isn't modified by this PR, so ownCloud will likely authorize access due to the bearer token, assuming the token is still valid. |
|
But the session is not extended on upload/download/propfind? I guess this would be a big architectural change to implement it like this. I fear this won't fix the use-case as in normal use the page is never refreshed. Edit: But at least this fixes the issue where you are always logged out if timeout is set. |
|
In general, I don't think it will give problems. If a download happens, once it's started it doesn't matter if the cookie expires. Unless the client has to perform a second request, which could have the cookie expired, the download should end without any issue. For the downloads in the web UI, the problem could be that the page refreshes "randomly" at some point, because it isn't clear what happens with the download that is in progress. If such random refresh doesn't happen (it shouldn't happen with the From my point of view:
|
|
Changes added to the PR:
Note that the new config option still needs to be added and documented in the config.php file. |
|
Main changes are already in the PR. There are a couple of non-code things left, to be done after validation: include information in the config.sample.php file about the new config option added, and add the changelog item. No plans to change anything due to sonarCloud: code smells are known, and the coverage doesn't seem to be easy to rise |
|
I have nothing to comment from a technical perspective. From a dont-break-everything-perspective it would be great to isolate this in an app on it's own ..... 99.99% of the installations don't need this feature .... |
|
SonarCloud Quality Gate failed. |
|
@jvillafanez so if I have an app e.g. video browser etc , and to be sure it does not get logout while browsing, it just needs to implement heartbeat with |
| $this->timeFactory = $timeFactory; | ||
| } | ||
|
|
||
| if ($request->getCookie(self::COOKIE_NAME) !== null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wonder why this part was done in constructor in the past
|
The basic setup is with the If The The new
There is a known issue with the In general, everything is managed for you with those 3 config options, so you don't need to touch anything else.
If you set the
|
Issue or design? :> btw, my bank website works the same way
what if I want to disable session_keepalive, but for certain app it should not logout? can apps somehow use heartbeat functionality in the app code to prevent logout when using the app ? |
Cookies work like that.
They can but I don't think they should, at least for now. |
| $this->setUser(null); | ||
| $this->setLoginName(null); | ||
| $this->unsetMagicInCookie(); | ||
| OC::$server->getSessionCryptoWrapper()->deleteCookie(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not want to be picky, but might need to go to constructor.. I know this would cause massive changes chain.. your call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave it there for now. I agree the service should be injected, but it isn't the only one. In addition, the class has a bunch of dependencies already, so we might need to consider a UserSessionHelper to act as a facade of some services to offload some of those dependencies. So it seems we might need a refactor here at some point.
mrow4a
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small comments but in general concept looks good. do not forget documentation.
|
@mmattel added owncloud/docs-server#283 in order to document this. |
|
One thing that might be worthy to notice is that the While all of this isn't expected to happen on any common browser, there could be clients that misbehave. In this case, the session will still be active in the server, so they could still access ownCloud without re-authenticating, assuming the session is still alive in the server (which is controlled by the I think it's important to note that the behavior isn't enforced by the server, but a hint for the clients. As explained, I don't think we can enforce the behavior server-side because the client might not trigger the "unload" event and the server might not know when the client has closed. |
|
Confirmed fixed in 10.10.0 RC2 |








The oc_sessionPassphrase cookie will always be sent for all the non-ajax
requests in order to update the expiration time accordingly. The
expiration time will match the one set in the 'session_lifetime'
configuration in config.php. If the 'session_lifetime' isn't set, the
expiration for the cookie will be set to "session" time.
If the 'session_keepalive' isn't set as false, a periodic "heartbeat"
request will be performed to prevent the browser session from being
expired. The "/heartbeat" will always update the expiration time for the
oc_sessionPassphrase cookie.
Login out will cause the cookie to be deleted.
Description
Usually, an auth cookie is sent without explicit expiration, so it will last for the whole browsing session.
If
session_lifetimeis explicitly set, the cookie will have the corresponding expiration time. Once the cookie expires, the browser will stop sending the cookie, which will cause the user to be kicked out and he'll have to login again.(Minimum expiration time for the cookie is 60 secs. Setting the
session_lifetimeto an equal or lower value will likely cause problems)Loading pages will cause the cookie expiration to be refreshed. This will allow extending the period where the user can perform actions in ownCloud. Note that this doesn't apply to ajax requests. In particular, browsing through the files page won't prevent the user from being kicked out.
Unless the
session_keepaliveis explicitly set to false, a periodic heartbeat request will be sent to the server. The "/heartbeat" endpoint will always refresh the cookie's expiration time. The "heartbeat" request is expected to happen everysession_lifetime / 2secs. This will help preventing the cookie from being expired.Login out will remove the cookie. A new one will be generated.
Note that this have been only tested with basic auth. Other authentication mechanisms haven't been tested yet, so there could be problems with those.
Also note that the behavior is mostly related to the browser. In order to refresh the expiration time for the cookie, we have to send a cookie to overwrite the old one, otherwise the browser won't send the cookie if it's expired.
NOTE: Additional features described in #39916 (comment) have been added
Related Issue
https://github.com/owncloud/enterprise/issues/5067
Motivation and Context
How Has This Been Tested?
Manually tested with basic auth
session_lifetime = 120andsession_keepalive = false(*) After those 2 minutes, you have to perform any request to the server. If you have the notifications app enabled, a request is performed automatically each 30 secs, so worst case, you are logged out after 2 minutes and a half. If you don't have the notifications app enabled, you'll have to perform any request by yourself.
session_lifetime = 120(session_keepaliveis unset)Screenshots (if appropriate):
Types of changes
Checklist: