U4-7495 - Back Office Not Respecting KeepUserLoggedIn Setting

Created by Nicholas Westby 03 Dec 2015, 18:51:56 Updated by Shannon Deminick 25 Jan 2016, 09:50:30

Relates to: U4-7538

Relates to: U4-7821

I have keepUserLoggedIn set to true in the umbracoSettings.config and umbracoTimeOutInMinutes set to 9999 in the web.config. When I ran my site, I noticed the UMB_UCONTEXT is set with an expiration date a few days in the future. I had a meeting with somebody for 30 minutes or so, then when I came back I was logged out and the cookie was deleted.

To reproduce, clone this repo at this tag ("second-logout-issue"): https://github.com/rhythmagency/formulate/tree/second-logout-issue

That's using Umbraco 7.3.3 (currently, the latest release). Run the website from Visual Studio 2013 in Chrome. Run the Umbraco installer with the defaults. Log out (to get rid of the session cookie). Log back in (to get the expiring cookie). Wait for 30 minutes or so. Try to navigate (I can't remember if this was necessary... might have just automatically shown the login screen) and check your cookies. The UMB_UCONTEXT should have been deleted.

This issue is related: http://issues.umbraco.org/issue/U4-7464

15 Attachments

Comments

Nicholas Westby 03 Dec 2015, 18:53:29

Note that I'm on PST (California) time. To be sure you can reproduce this, you may or may not want to change your system clock to that timezone.


Brian Powell 03 Dec 2015, 18:56:36

FWIW, I've left Umbraco windows open overnight last night and didn't experience any problems. I have keepUserLoggedIn set to true and a 30 minute timeout in web.config. I'm in the EST (New York) time zone. The v7.3.3 fix seems to be working OK for me.


Nicholas Westby 03 Dec 2015, 19:26:43

@bitmapped My theory is that it worked for you because you left the timeout at 30 minutes. I bet if you increase it to 9999, you too will experience this issue.


Nicholas Westby 03 Dec 2015, 19:29:38

Here's what my network tab looks like for most requests (notice there are no response cookies):

!1.png!

After about 30 minutes, I see this in the network tab (notice it has 3 response cookies, one of them being UMB_UCONTEXT with an expiration of 1970):

!2.png!

The subsequent request looks like this (notice it is now missing UMB_UCONTEXT from the request):

!3.png!


Nicholas Westby 03 Dec 2015, 19:32:26

If anybody is curious, here is the URL in that last red request shown in the screenshot: http://localhost:49303/login.aspx?ReturnUrl=%2fumbraco%2fbackoffice%2fUmbracoApi%2fAuthentication%2fGetRemainingTimeoutSeconds

And Umbraco doesn't appear to be logged out until I click on something (e.g., if I try to navigate to a different section). When I click something, it shows the login screen.


Nicholas Westby 03 Dec 2015, 19:34:01

Also, the response of that red URL is 404 with this content:

Page not found

No umbraco document matches the url '/login.aspx?ReturnUrl=%2fumbraco%2fbackoffice%2fUmbracoApi%2fAuthentication%2fGetRemainingTimeoutSeconds'.

This page can be replaced with a custom 404. Check the documentation for "custom 404".

This page is intentionally left ugly ;-)

It looks like it's trying to send me to the login page, but is getting the URL incorrect.


Nicholas Westby 11 Dec 2015, 20:45:05

Looks like this is also happening with Umbraco 7.3.4.


Shannon Deminick 14 Dec 2015, 09:11:00

I think I know why this is happening, as a work around, don't change your timeout to 9999... there is no point to this if you have keepUserLoggedIn = true.


Stefan Kip 15 Dec 2015, 13:59:33

Experiencing the same; getting logged out of the back-office while keepUserLoggedIn is set to true. Really annoying when you're trying to arrange the back-office.


Shannon Deminick 15 Dec 2015, 14:05:46

@kipusoep What version are you using now? Did you see my above note? Do you have some strange setting for umbracoTimeOutInMinutes? In latest 7.3 having keepUserLoggedIn = true works, i've tested it a number of times now, so long as you don't have some wacky value for umbracoTimeOutInMinutes.

Please please please, when writing bug reports, please be detailed, please provide exact steps to reproduce. Think about how you'd like to receive a bug report.


Stefan Kip 15 Dec 2015, 14:07:32

I've got it set like so (version 7.3.3 btw):


Shannon Deminick 15 Dec 2015, 14:08:44

Change it back to the default = 20 or 30 , it will work ... this is mentioned above


Stefan Kip 15 Dec 2015, 14:09:13

I'll give it a try and let you know how it goes, thanks :-)


Shannon Deminick 15 Dec 2015, 16:19:26

NOTE for reviewers, see issue: http://issues.umbraco.org/issue/U4-7538 since it's the same PR for both


Stefan Kip 15 Dec 2015, 19:38:57

Seems to be working so far, I'll try some more tomorrow. Though the reason I'm setting keepUserLoggedIn to true, is because the timeout mechanism seems to be using an abolute expiration and not a sliding expiration. E.g. it seems to me that when I log in, I have 20 minutes or so to do work and then I get logged no matter what. Like I said, this seems to be the case for me.


Stefan Kip 16 Dec 2015, 12:09:52

So like I said, it works with keepUserLoggedIn set to true. But what's the expected behavior if you've got it set to false with umbracoTimeOutInMinutes set to the default 20? And how about when you set it to 240 for example? Should it be a sliding expiration or absolute?


Shannon Deminick 16 Dec 2015, 12:18:34

I made some fixes yesterday in 7.4 (beta out soon... but we might backport to a 7.3.x version if necessary). What I discovered was: Regardless of keepUserLoggedIn, it will always keep you logged in - so long as you have a 'normal' timeout set like 20 or 30. This was because the normal cookie middleware was still executing for the getuserseconds request which means it would renew the cookie

The expected behavior (which is fixed in 7.4) is:

  • with keepUserLoggedIn=true: it will create the cookie with the timeout specified by umbracoTimeOutInMinutes. It will renew this cookie when there is less than half of the amount of time specified by umbracoTimeOutInMinutes remaining on the ticket and it will be renewed with a new time of Now()+umbracoTimeOutInMinutes
  • with keepUserLoggedIn=false: it will renew the cookie if the user is active (i.e. clicking on stuff, making requests) based on the same logic above. If the user is inactive, the calls to getuserseconds does not renew the ticket and it will expire based on it's expiration date


Shannon Deminick 16 Dec 2015, 12:19:58

The above behavior listed for keepUserLoggedIn=true is also the case in 7.3.4


Nicholas Westby 17 Jan 2016, 06:05:30

@Shandem This appears to still be happening in Umbraco 7.3.5. Here's the request that responded with cookies that logged me out:

!still-happening.png!

Note that the "GetEntityChildren" is an action method on an API controller of mine. The request responded with 401 unauthorized (as I'd expect from a request made while logged out). It's secured like this:

[PluginController("formulate")] [UmbracoApplicationAuthorize(CoreConstants.Applications.Users)] public class EntitiesController : UmbracoAuthorizedJsonController {

As was the case before, this is in my web.config:

And this is in my umbracoSettings.config:

true

You can confirm this yourself by downloading/cloning the repo at this commit: https://github.com/rhythmagency/formulate/tree/ab5babef105081cb8a352d0c5c22793e3d535650

I'm guessing the same steps to reproduce that applied before apply now, but I'm not sure. I've noticed this about 3 times today. For the latest time, I made sure to clear all my cookies (and browser cache) before I attempted to reproduce. After what felt like 30 minutes to an hour of developing the plugin I'm making, I got the login screen.


Shannon Deminick 19 Jan 2016, 15:28:27

Hi @Knickerbocker ... I'm not sure if you are testing with these settings because you like pain, or haven't read the previous comments, or just want to prove that we haven't actually fixed the issue? In any case, as previously mentioned, the workaround was to not use 9999 as a setting and instead use 30, then you wouldn't have had any issue in 7.3.4 under normal circumstances. In 7.3.5 we have actually fixed the issue, the problem you are now seeing is that your WebApi controller is not considered a back office controller because you are missing the [IsBackOffice] attribute which tells Umbraco to authenticate the request for back office purposes. AuthN and AuthZ are different, just because you are inheriting from UmbracoAuthorizedJsonController doesn't mean that AuthN will run for the back office (this is based on specific routes), the UmbracoAuthorizedJsonController is for AuthZ only. the [IsBackOffice] configures auto-routed UmbracoApiControllers to be routed with back office routes and therefore they have AuthN applied to them.


Shannon Deminick 19 Jan 2016, 15:31:32

I've proven myself wrong here, the UmbracoAuthorizedJsonController does have an [IsBackOffice] attribute applied, so it should be routed correct, what is the path of your GetEntityChildren? And also can you just test without 9999 ?


Nicholas Westby 19 Jan 2016, 17:07:41

@Shandem I'm testing with these settings because that's what I typically use and that's what I have recommended my coworkers use and that's what I suspect many people will do (i.e., just change all the relevant settings to "max" to avoid logouts).

FYI, I suspect my controller has nothing to do with the issue, though there is the off chance that it does. I'm guessing that I just happened to hit that controller at the right time.

Sure, I can test without the 9999, but that's already a known workaround, so I suspect that will work just fine. If that would give you some useful information, however, I can do that. Regardless of it working with that setting reverted to its original value, keepUserLoggedIn should work for any value of umbracoTimeOutInMinutes (aside from perhaps very low values).


Shannon Deminick 19 Jan 2016, 18:31:10

Righto. Well the way that cookie renewal works is by OWIN, the cookie is renewed when it's halfway completed through the umbracoTimeoutMinutes, because this value is used to set the CookieAuthenticationOptions.ExpireTimeSpan. We could simply ignore the umbracoTimeoutMinutes if keepUserLoggedIn is true and set it to 10 minutes (or whatever) so that the cookie is renewed every 5 minutes.

So it would actually help if you could set this to a low value and see if you ever get this issue, if you don't we could go ahead and make this change. That said, I'd still be interested to know why/how you can get logged out. I suppose this could be caused by numerous factors like running another umbraco site on local host during development, something to do with logic in your own code, possibly stepping through code for a long period of time might cause this since requests are not being made.

I'd need specific steps to reproduce before I spent 30+ minutes trying to mimic what you are doing whilst developing the plugin you are making. I can test simply having these settings and leaving the back office open for more than 30 minutes (or longer), if that works, then we can only presume something else is at play.


Nicholas Westby 20 Jan 2016, 00:52:05

@Shandem I reproduced it outside of my website in which I'm building my plugin, so I'll write the steps down here for you to reproduce.

First, change your timezone to Pacific Time:

!time.png!

Download Umbraco 7.3.5. Unzip into a folder. Setup a website in IIS. Set permissions and a domain name (I used "www.timeout.com"). Modify your hosts file so www.timeout.com points to 127.0.0.1. Start the website in Chrome. Run the Umbraco install wizard using the defaults. Log out. Close your browser window. Open it again and clear all your caches and close it again.

Change the web.config to 9999 and the umbracoSettings to true.

Open Internet Explorer. Clear all your caches. Close IE. Recycle the application pool on your website. Open IE and navigate directly to www.timeout.com/umbraco. Log in. Open F12 developer tools. Navigate to the network tab. Ensure to deselect "clear entries on navigate". Ensure you are capturing traffic. Refresh the page. Wait 86 minutes (obviously, that was an arbitrary amount of time I happened to have waited). You'll see many requests for GetRemainingTimeoutSeconds:

!requests.png!

Click on the root-level node. You will see the login screen (i.e., you will be logged out). Here are the cookies before, during, and after that click:

!cookies-1.png!

!cookies-2.png!

!cookies-3.png!

The first is the request before I was logged out. The second is the request that logged me out. The third is the login screen (i.e., the request after I was logged out).

You can see the second request got a response cookie that expired the UMB_CONTEXT cookie by setting the date to 1970 (a common epoch).


Shannon Deminick 20 Jan 2016, 09:32:15

Ok thanks. If you have another 86 minutes to spare, could you test this when it's 30 instead of 9999 and see if that fixes it? The 9999 (umbracoTimeOutInMinutes) is used for cookie + ticket expiry, the cookie + ticket is only renewed when it reaches half way through this time. In this case the cookie + ticket should still be accepted since it shouldn't be expired yet. Let me know if you can test this, otherwise we won't be able to find any time to look at this for another couple of weeks, there are critical tasks and releases we are focusing on now.


Nicholas Westby 20 Jan 2016, 17:53:36

@Shandem Sure. I have just started the site (after changing from 9999 to 30). As luck would have it, I have an hour-long meeting now. I'll check on it after I'm out of the meeting.


Nicholas Westby 20 Jan 2016, 19:48:02

@Shandem I tested for over an hour and I was not logged out. Here's the network trace in F12 developer tools:

!network-fine.png!

Most of the time, the cookies look like this:

!most-cookies.png!

Every 27 or so cookies look like this (i.e., the server responds with a cookie to renew the client cookie):

!cookie-26.png!

!cookie-53.png!

!cookie-80.png!

!cookie-107.png!

Since the GetRemainingTimeoutSeconds seems to occur every 30 seconds or so, that means the cookie is being renewed every 15 minutes or so. That makes sense (half of the 30 minutes, like you said).

As expected, setting the umbracoTimeoutInMinutes to 30 works perfectly fine. It is the combination of setting keepUserLoggedIn to true and umbracoTimeoutInMinutes to a larger value that does not work.


Shannon Deminick 20 Jan 2016, 19:52:42

Thanks!!!! Really appreciate you testing and confirming this. So what we'll do is ignore the custom renewal time when keep user logged in is true and just use 30


Nicholas Westby 20 Jan 2016, 21:14:29

@Shandem Will that work if I log in, close my browser, and open it back up the next day? My concern is that it would not (but should) stay logged in. In other words, if there is a no browser open to make the periodic request to GetRemainingTimeoutSeconds, my guess is that what you are proposing would not keep me logged in if I close my browser for an extended period of time.


Shannon Deminick 20 Jan 2016, 21:44:27

What I'm proposing is the ticket renewal periods not the expiry. In any case, when I have some time I'll investigate options and try to determine how your ticket gets timed out with your 9999 settings.


Priority: Minor

Type: Bug

State: Fixed

Assignee:

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions: 7.3.5

Due in version: 7.4.0, 7.3.5

Sprint: Sprint 5

Story Points:

Cycle: