I have my own asp.net cookie created like this:
var authTicket = new FormsAuthenticationTicket(
version,
userName,
DateTime.UtcNow,
DateTime.UtcNow.AddMinutes(30),
createPersistentCookie,
userData,
"/");
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
As you can see everything is in UTC time.
When I decrypt it:
var cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
var ticket = FormsAuthentication.Decrypt(cookie.Value);
return ticket.Expiration.Ticks;
}
else
{
return 0;
}
It returns local time. So, does it get converted automatically or is it something else? If so how can I get it back to UTC time?
From MSDN:
FormsAuthenticationTicket.Expiration Property
Gets the local date and time at which the forms-authentication ticket expires.
You can use the DateTime.ToUniversalTime method to convert a DateTime to UTC:
return ticket.Expiration.ToUniversalTime().Ticks;
As you've seen, once the FormsAuthenticationTicket has been serialized to a cookie and deserialized, the Expiration and Issue times will always be local.
The Remarks section in MSDN says "If the FormsAuthenticationTicket was created using a constructor that takes an expiration parameter, the Expiration property returns the value supplied to the expiration parameter.". Hence if you pass UTC, you will get back UTC until the ticket has been serialized/deserialized, after which it will be converted to local.
If you supply issueDate and expiration to the constructor, they should normally be in local time. However no attempt is made to convert them to local time - probably the reason for this is for backwards compatibility with .NET 1.x.
With .NET 1.x the DateTime struct did not have a "Kind" property, so there was no way to tell it the caller supplied UTC or local time - it was just assumed to be local.
Therefore I suggest you change your code to pass local time to the FormsAuthenticationTicket constructor, though it does expose you to this bug recorded on Microsoft Connect.
Related
I try to delete this cookie:
First of all a bit of background. This is a token for verification on different sites within the same domain. I make the central login page. This page is working fine, except the log out. Every other cookie, I want to delete, gets deleted by JQuery cookie $.removeCookie('cookieName'). And I know, I can't delete this from the JavaScript, because of the secure-flag.
So I tried deleting it from a controller method. I call this method via ajax from JavaScript.
$.ajax({ur:'/Login/ExpireToken'})
I can see that it works in the Chrome Console Network Tab.
public void ExpireToken()
{
Response.Cookies.Remove("crowd.token_key");
}
But this, I don't know why, makes a new cookie, with the same name, empty value, the whole domain of the login page and no flags set.
So I tested, if the backend can find the cookie I want.
public string ExpireToken()
{
return Response.Cookies["crowd.token_key"].Value;
}
It returns the correct value and doesn't create a new/false one.
After this I tried to set the expires field to one day in the past or to now. I don't know, why this should work, because the expiration date of this cookie is already in the past.
public void ExpireToken()
{
Response.Cookies["crowd.token_key"].Expires = DateTime.Now.AddDays(-1d);
}
And guess what, it doesn't work. It does literally nothing.
Other ways that don't work
if (Request.Cookies["crowd.token_key"] != null)
{
var c = new HttpCookie("crowd.token_key");
c.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(c);
}
As per the doc, you are doing things right in your las attemp, the one setting the expiration date to yesterday. Quote:
The technique is to create a new cookie with the same name as the
cookie to be deleted, but to set the cookie's expiration to a date
earlier than today. When the browser checks the cookie's expiration,
the browser will discard the now-outdated cookie
I would put a breakpoint and debug to check cookie names, if everything is fine, perhaps the web browser is missbehaving.
HttpCookie aCookie;
string cookieName;
int limit = Request.Cookies.Count;
for (int i=0; i<limit; i++)
{
cookieName = Request.Cookies[i].Name;
aCookie = new HttpCookie(cookieName);
aCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(aCookie);
}
I'm setting a cookie like so:
protected void SetCookie(bool value, int expiration)
{
var cookie = Response.Cookies[COOKIE_NAME] ?? new HttpCookie(COOKIE_NAME);
cookie.Value = value.ToString();
cookie.Expires = DateTime.UtcNow.AddDays(expiration);
Response.Cookies.Set(cookie);
}
In the SetCookie function, when I inspect the cookie on the last line, the Expiration is set to tomorrow's date.
However, when I retrieve this cookie on the next page load:
var cookie = Request.Cookies[COOKIE_NAME];
the cookie exists, but the expiration date is the default date value of 1/1/0001 12:00:00 AM
I believe the expiration is a client-side thing. The browser should send any not-expired cookies, but does not send the expiration date (only name and value). I think you should re-set and refresh the expiration on each request.
This was the first format reference I found: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie
If for whatever reason you need to retrieve the expiration data server side, I would include it in the cookie contents or set a secondary cookie to contain that information.
I am creating a website, and I'm not sure how to use sessions with cookies.
When sessions timeout, I want to show the username and time of the user; for e.g., username stored in cookies and session. When sessions timeout the username must be retrived from the cookies.
Lets put things in perspective first.
A session is the session a user is experiencing when he is using the website.
How it works is basically a user starts a session with the web server, the web server then gives it a key of the session and sets a timeout for the session which are stored as a cookie.
Since this process is automatic and you can only configure it in web.config (unless you are asp.net core vNext, which I doubt) with sessionState https://msdn.microsoft.com/en-us/library/h6bb9cz9%28v=vs.80%29.aspx
A normal HttpCookie on another hand is something you set on your Response object and can give it a specific expiration date like this:
HttpCookie myCookie = new HttpCookie("MyTestCookie");
DateTime now = DateTime.Now;
// Set the cookie value.
myCookie.Value = now.ToString();
// Set the cookie expiration date.
myCookie.Expires = now.AddMinutes(1);
// Add the cookie.
Response.Cookies.Add(myCookie);
Which suits your needs more likely.
If you want more information about sessions expiration I'd also suggest you check out http://www.hanselman.com/blog/TroubleshootingExpiredASPNETSessionStateAndYourOptions.aspx
I have been searching the web and found many odd answers and i've tried almost all of them.
My problem is this. My login page contains:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(min), persistCookie, userid.ToString());
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Expires = ticket.Expiration;
Response.Cookies.Add(cookie);
FormsAuthentication.RedirectFromLoginPage(userName, persistCookie);
Now the min value is per user based and can be set individually, so is persistCookie.
After what i understand this code should result in the possibillity of overriding the default values in web.config. Which should be 30 minutes.
<authentication mode="Forms">
<forms loginUrl="~/Default/default.aspx" defaultUrl="~/User/UserMain.aspx"/>
</authentication>
min is currenlty set to 120, and persistCookie is set too true. When i log in i get timeout at 30 minutes. (Not session, so somewhere expiration date is set, because if it was not set the cookie should be session based, also i do not get 120 minutes which is kind of the deal here)
My question, for simplifying it, is how do i get the value 'min' to be the expiry date of the cookie?
This might turn out too be a simple thing but i am currently totally stuck so any help would be appriciated.
EDIT:
I changed the login logic to this:
FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(min), persistCookie, userid.ToString());
string encTicket = FormsAuthentication.Encrypt(fat);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Expires = fat.Expiration });
Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, false));
And now it works. But i cant seem to figure out why this would work, and not the previous one.
Ticket creation is the same, the only difference is that i add Expires property of the HttpCookie when creating the HttpCookie, not after the object is made.
If anybody has a good explanation i am all ears! :)
The problem with your code is that you're calling RedirectFromLoginPage, which will create the forms authentication cookie, overwriting the cookie you've just created:
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Expires = ticket.Expiration;
Response.Cookies.Add(cookie);
FormsAuthentication.RedirectFromLoginPage(userName, persistCookie); <-- creates a new cookie
The cookie created by RedirectFromLoginPage will of course have the default timeout taken from configuration.
Your second version is the way to go.
I think you don't understand the difference between cookie expiration and ticket expiration dates - ticket can be considered as expired even if the cookie it is being stored in is still valid. The 4th param of FormsAuthenticationTicket constructor is responsible for the ticket expiration date.
So, to answer your question, you need to manually set expiration date of your cookie or make it long enough to exceed expiration date of your authentication ticket.
I use a javascript function to store the cookie:
createCookie("teaser", "teaser", 7);
function createCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toGMTString();
}
document.cookie = name + "=" + value + expires + "; path=/";
return value;
}
And when I check the cookies in my browser the cookie expiration of teaser is correctly set:
25. oktober 2011 16:12:17
But when in C# i go to get the value, the expiration date is set to 01.01.0001.
var cookie = Request.Cookies["teaser"];
if (cookie != null && teaserList.Count() > 0)
{
cookie.Expires is 01.01.0001
Any clue?
Egghead says that:
The browser is responsible for managing cookies, and the cookie's
expiration time and date help the browser manage its store of cookies.
Therefore, although you can read the name and value of a cookie, you
cannot read the cookie's expiration date and time. When the browser
sends cookie information to the server, the browser does not include
the expiration information. (The cookie's Expires property always
returns a date-time value of zero.) If you are concerned about the
expiration date of a cookie, you must reset it.
The browser does not transmit the expiration date of a cookie to servers, this is as per HTTP specification.
Browsers only send the cookie name and value only.
The Expires property on the cookie object is only used when setting expiration date on a cookie that is going to be written in a response, not read in a request.
When reading the cookie is Expires property value is always going to be null. You can see this for yourself by examining the HTTP headers. If you really want to read the expire value of a cookie, try writing it in the value itself, or using another cookie with the value of the expiration date (you will need to keep them in sync yourself).