I'm using Forms Authentication fairly successfully, but have run into a strange issue. I've looked around the web, and haven't found the answer thus far.
I'm using some Javascript to determine when the current session is 60 seconds away from timing out, and if so - pop up a dialog box with a button which, if pressed, will extend the current FormsAuthentication ticket.
This is the code I'm using to renew the ticket. I'm simply add 5 minutes to the current expiration date of the ticket. But when I output the new expiration date, it's always under 5 minutes; normally 4 minutes and some seconds.
The code:
string userID = HttpContext.Current.User.Identity.Name;
HttpCookie cookie = FormsAuthentication.GetAuthCookie(userID, true);
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
DateTime NEW_EXPIRY = DateTime.Now.AddMinutes(FormsAuthentication.Timeout.Minutes);
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(
ticket.Version,
userID,
DateTime.Now,
NEW_EXPIRY,
ticket.IsPersistent,
ticket.UserData,
ticket.CookiePath);
cookie.Value = FormsAuthentication.Encrypt(newTicket);
if (ticket.IsPersistent) cookie.Expires = newTicket.Expiration;
cookie.Secure = FormsAuthentication.RequireSSL;
HttpContext.Current.Response.Cookies.Add(cookie);
So, here's an example output of the time differences:
The time stamp now = 16/01/2016 14:03:28 ticket expires=16/01/2016 14:07:49 (TOTAL SECONDS=261.0857244)
Why is it not resetting the expiration time to exactly 14:08:28?? I'm banging my head on the wall here...
Ok so I still don't know why the expiration value from the FormsIdentity object is incorrect... so what I've done is passed the actual new expiration value (as a DateTime) back from the renewal method,and relied on that. So it seems that this value is correct, and that's the value I should be using to determine the real time out value.
Does that even make sense? I dunno, but it's working now!
Related
If you set a cookie's expiration to DateTime.Now.AddDays(-1), when would it expire? It shows that the expiration is yesterday. Here is the code:
var rememberMeCookie = new HttpCookie("remember_me");
rememberMeCookie.Expires = DateTime.Now.AddDays(-1);
There is no HTTP Header to delete the cookie, when you click "Logout", this is a trick to confuse browser with previous expiration date, so browser will immediately delete cookie from its store.
This question is like you bought a milk on 11/09/2015 but expired on 10/09/2015, then you ask:" should i drink it?" Of cause not! because expired is 'YESTERDAY' like you said.
you cannot get anything from a expired cookie.
Okay, I've been assigned with authenticating used on a login page. I've been working on this for quite a while and decided to clean up it up. The problem that I faced is one of those problems where exceptions aren't thrown, no error is generated, and everything looks okay, but when you try to use a function, it gives back a result that you don't want.
The code I used looks very similar to code from this page:
http://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationticket.aspx
I've used the code from the demo in my project:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
username,
DateTime.Now,
DateTime.Now.AddMinutes(30),
isPersistent,
userData,
FormsAuthentication.FormsCookiePath);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
// Create the cookie.
Response.Cookies.Add(myCookie);
So if I logged in, everything works and the below code evaluates to true:
HttpContext.Current.User.Identity.IsAuthenticated;
However, if I wanted to include subkeys to myCookie using either versions:
myCookie.Values.Add("userName", "patrick"); //version 1
myCookie.Values["userName"] = "patrick"; //version 2
Then you add to the cookies collection:
Response.Cookies.Add(myCookie);
Then refresh the page after login:
//This always set to false even after successful log on
HttpContext.Current.User.Identity.IsAuthenticated;
No clue why!
I wanted to do something where I don't have to add the encryption value to the httpcookie immediately:
//IsAuthenticated doesn't work = false
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormCookieName);
cookie.Values.Add("encryptTicket", encTicket);
It's just weird that adding subkeys don't work at all. And that I am forced to encypt a ticket in order to make it work. What I mean, is that IsAuthenticated is false all the time, logged in and authenticated or not. Can anyone try to explain what's going on with this? I have a working solution, but any insight would be helpful.
Okay, think I figured this out. It's because of how my web.config was set up for forms authentication. Using the forms tag.
The FormsAuthenticationTicket looks at that tag for specific information, and if I didn't create a cookie off of it, it wouldn't authenticate me. This was also defaulted to cookieless mode to UseCookies.
But anyways, after I create a cookie off of that, then I become authenticated and then a new session is created for me. After that, I can then provide any extra cookies I want and let the website use them as needed. But as long as that AuthCookie (in my case .ASPXAUTH) is valid, so is my authentication session.
In fact, when I tried to make a cookie session end when the browser closed, by setting the expiration date to MinValue for the cookie and the ticket, I wasn't able to authenticate either! I had to make the ticket last longer than the actual cookie so that the ticket doesn't expire before the cookie does.
The ticket information is really a configuration used to make the cookie, and after cookie creation, the browser is what defines how the cookies are used.
This seems like it should be pretty straightforward. However, for the life of me, I can't seem to create a cookie in ASP.NET MVC. Currently, I have the following code:
DateTime lastActivityDate = DateTime.UtcNow;
if (Request.Browser.Cookies)
{
HttpCookie lastActivityCookie = new HttpCookie(COOKIE_LAST_ACTIVITY, lastActivityDate.ToShortDateString());
lastActivityCookie.Expires = DateTime.Now.AddMonths(-12);
this.ControllerContext.HttpContext.Response.Cookies.Add(lastActivityCookie);
}
I've set a breakpoint and noticed that the cookie appears to be getting added. (yes, I'm getting into the Request.Browser.Cookies block). I then attempt to retrieve the cookie using the following:
DateTime lastActivity = DateTime.UtcNow.AddDays(-7); // Default to the past week
HttpCookie lastActivityCookie = Request.Cookies[COOKIE_LAST_ACTIVITY];
if (lastActivityCookie != null)
{
DateTime temp = DateTime.UtcNow;
if (String.IsNullOrWhiteSpace(lastActivityCookie.Value) == false)
{
if (DateTime.TryParse(lastActivityCookie.Value, out temp))
lastActivity = temp;
}
}
Unfortunately, lastActivityCookie is always null. In addition, when I look in the "Resources" tab in Chrome, I see the cookies branch, however, the cookie I'm trying to create is not listed. There are two other cookies listed though, including the .ASPXAUTH cookie. What am I doing wrong?
Look at the Expires property of HttpCookie object - more on this here. I believe you shoud set cookie expiration date in future like in the example on msdn site. Because you set date time in the past the cookie automatically expires and you are never able to read it.
I am having trouble with the .Expires cookie attribute. It keeps coming back with 01/01/0001 12:00 AM, when I read the cookie back.
Here is the code. I added in the retrieve just below the save solely for debugging purposes. The save and retrieve happen in different places in the same file. I purposely did not specify a Domain, as I want the cookie to exist site wide.
The data shows up nicely, just not the expiration.
Note: I am testing under Visual Studio 2012 running under local host using .Net Framework 4.
System.Web.UI.Page oPage = this.Page;
HttpCookie oCookie = new HttpCookie("UserData");
// Set the cookie value.
oCookie.Secure = false;
oCookie["Field1"] = strField1;
oCookie["Field2"] = strField2;
oCookie.Expires = DateTime.Now.AddDays(1);
// Add the cookie.
oPage.Response.Cookies.Add(oCookie);
// Get the cookie.
oCookie = new HttpCookie("UserData");
oCookie = oPage.Request.Cookies["UserData"];
The browser will not send anything to the server except the cookie name and value. All of the other properties (expires, domain, path, httponly, ...) cannot be retrieved on requests after the cookie has been set.
The more accepted way to deal with this is to redirect the user to a login page when they try to access a protected resource and display some message along the lines of "You need to log in to view this page. If you were previously logged in, your session may have expired."
(Also note that you should be re-setting the cookie on every request, so that the user will not be logged out if they continue to use the site. It's not clear from your code whether you are doing this or not.)
I was just doing some more Google searching on my problem and saw this link, another posting here on Stackoverflow.
Cookies are always expired
I am also validating using the construct:
if (cookie != null && cookie.Expires > DateTime.Now)...
As several pointed out, expiration checking happens, if you can no longer retrieve the cookie. That is seriously dumb on whomever constructed this architecture. Yes, maybe there should be RequestCookie and ResponseCookie, the difference being ResponseCookie has no Expiry date.
The person who resopnded to me taught me that it is not just expires but other fields too.
In C# code, if using Form Authentication, You can find if cookie is persistent using below code
bool IsCookiePersistent = ((FormsIdentity)User.Identity).Ticket.IsPersistent;
Here Ticket will return the FormsAuthenticationTicket which has Expiration DateTime property.
I am using the following code for a custom "remember me" implimentation:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, member.UserName, DateTime.Now, DateTime.Now.AddHours(24), true, dataString);
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
faCookie.Expires = ticket.Expiration;
HttpContext.Current.Response.Cookies.Add(faCookie);
But some users cannot login (Login page appears even after sign in).
It seems the problem is caused by the client having a different (greater) date than the server.
So, what is the best and correct solution for a "remember me" implementation.
To solve this problem I must remove this line:
faCookie.Expires = ticket.Expiration;
After removing this line, when user closes the browser, he must sign in (cookie is not persist).
What is the solution?
What you could do is get the clients Date/Time and use that for the Cookie, rather than the server time.
There is a great answer here showing you a good way to do this; basically populate a hidden field with the clients date/time and get it on postback.
You could have this hidden field on your masterpage so the clients date/time is always available. doesn't need to just be on the login screen.