Cookie expiry date is always 1/1/0001 - asp.net-mvc

Description:
I'm using cookie in mvc project to remember most recent download format selected by user. While creating cookie, I'm setting expiry date for that cookie. And when I try to get that cookie and expiry date of that cookie then I'm getting "1/1/0001" as expiry date always. I'm not getting the reason behind this. please help to reason behind this.
Code:
1) Setting cookie and it's expiry date:
Response.Cookies.Add(new HttpCookie(base.LoggedOnUser.Email, exportFileFormat.ToString()));
var requestCookie = Request.Cookies[base.LoggedOnUser.Email];
if (requestCookie != null)
{
requestCookie.Expires = DateTime.UtcNow.AddDays(Convert.ToInt32(ConfigurationManager.AppSettings["FileFormatTypeCookieExpiry"]));
}
2) Getting cookie and it's expiry date:
var fileFormatTypeCookie = HttpContext.Current.Request.Cookies[CurrentUser.Email];
if (fileFormatTypeCookie != null && fileFormatTypeCookie.Value != null)
{
var exportFileFormat = fileFormatTypeCookie.Value;
var expiry = fileFormatTypeCookie.Expires;
}
Above variable expiry is always "1/1/0001".

I quote the answer from MikeSmithDev from a possible duplicate question:
Why is the cookie expiration date not surviving across sessions in ASP.NET?
The Short Answer - You cannot read the cookie's expiration date and
time.
Slightly Longer Answer - This is not an issue of sessions in ASP.NET.
It is an issue of what you can read from a cookie server-side in
ASP.NET. Per the MSDN:
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.)
You can read the Expires property of a cookie that you have set in the
HttpResponse object, before the cookie has been sent to the browser.
However, you cannot get the expiration back in the HttpRequest object.
So basically, the cookie expiration date is set correctly. This can be
verified by inspecting the cookie in the browser. Unfortunately,
reading this cookie like in your Get function will return 1/1/0001.
If you really want to get the expiration, then you'd have to store it
in the cookie itself:
Set
DateTime exp = DateTime.Now.AddDays(1);
HttpCookie PreferredCookie = new HttpCookie("PreferredCookie");
PreferredCookie.Values.Add("cookieType", "Zref");
PreferredCookie.Values.Add("exp", exp.ToString());
PreferredCookie.Expires = exp;
Response.Cookies.Set(PreferredCookie);
Get
HttpCookie PreferredCookie = Request.Cookies["PreferredCookie"];
if (PreferredCookie != null)
{
CookieLiteral.Text = "Value = " + PreferredCookie["cookieType"] + "<br>";
CookieLiteral.Text += "Expires = " + PreferredCookie["exp"];
}
else
{
CookieLiteral.Text = "No Cookie";
}

Related

Session Authentication not working in Play when using Silhouette

I am using Silhouette security library. My Play server seem to send empty Session information in response. What am I doing wrong?
Following is the print on Play's console just before sending response.
Session(Map(authenticator -> 1-jtwBvA+LsLKE2rnkT/nMH1aQF9xc1twhECrma9mj3NUhUdVDmh/4wxQ2MxDOjcxkvEMTi1k63Dg5ezl+9FzDE3miaM5DbOrhyqAyGu4+30mHHV3QdPKA3IQQx5UdL1Hu85fZRI4f3Ef+q6xAgboDps0uBob5ojzo5Oqy8FNsoexn7Wr9iRyTr5xrMrLvl9GNQa+rA3q8qvW84sJaSei2iydrP2OjUbnnzo+zgrHLB3Bn7KJxOcFH4h9CikZNk/FHbtDm4uxzcK3paK1CuuIWLE8yvcYdavJ+4ejV5IaJ8QesJQRFgBktD9L/A2bc03eaA8wm)))
But in the the browser window, I notice that the value is empty.
Set-Cookie: PLAY_SESSION=; Max-Age=-86400;
Note that my browser earlier already had a PLAY_SESSION cookie from previous test runs. However, I would expect that the client application (Angular) would override old cookies with new cookies. Am I correct?
Following is the code snippet which creates, initialised and embed session information
val AuthenticatorFuture: Future[SessionAuthenticator] = silhouette.env.authenticatorService.create(loginInfo) //create authenticator
AuthenticatorFuture.flatMap(authenticator => { //got the authenticator
val securityTokenFuture: Future[Session] = silhouette.env.authenticatorService.init(authenticator) //init authenticator
securityTokenFuture.flatMap(securityToken=> {
println("adding security token: ",securityToken)
val result:Future[AuthenticatorResult] = silhouette.env.authenticatorService.embed(securityToken, Ok(Json.toJson(JsonResultSuccess("found user"))))
result
The Environment is defined as
trait SessionEnv extends Env {
type I = User
type A = SessionAuthenticator
}
As is passed to my controller as
silhouette: Silhouette[SessionEnv]
I created is at compile time as follows
val configSession = SessionAuthenticatorSettings()
val sessionAuthenticatorService = new SessionAuthenticatorService(configSession,fingerprintGenerator,authenticatorEncoder,new DefaultSessionCookieBaker(),clock)
val sessionEnv = com.mohiva.play.silhouette.api.Environment[SessionEnv](userIdentityService,sessionAuthenticatorService,Seq(),EventBus())
The issue is probably expected behavior of Play Framework as Silhouette doesn't modify the session cookie. I noticed that the browser already had a previous expired cookie and it sends it in the signin request. When Silhouette authenticator sees the expired cookie, it sends an empty value back. I think this is to make the browser discard the previous cookie.

Can you reuse a Google service account access token?

Using the Google API PHP Client with a service account, it returns an array like the following:
array (size=3)
'access_token' => string '...TOKEN...' (length=127)
'token_type' => string 'Bearer' (length=6)
'expires_in' => int 3600
Is it best practice to generate a new token every page request? It seems wasteful to do so when each token is valid for one hour. But since the token does not include a created value or a token_id value, the builtin isAccessTokenExpired() method will always return true, meaning it is always expired.
I see several options for reusing the same token:
Option 1: When token is created via fetchAccessTokenWithAssertion(), I can manually add a created value to the token array with time() as its value. Then save that to session/database so later when isAccessTokenExpired is called it will have that field to verify.
Option 2: Save token to session/database along with the timestamp the token will expire (time() + $token['expires_in']), and then on subsequent views I can do my own calculations to verify that the token is still in a valid time period. This seems a bit weird too though as I can't be fully sure that Google has not revoked the token or anything funny like that.
Option 3: Call a method that uses the access token and checks its response. If the call succeeded then the access token must be good still, if not then I can go ahead and ask for a new one. But what method could I call? One that would only need the most basic permissions would be good.
Thank you.
You can request a new token each time, but it's needless overhead and I believe it can eat into your API call quota as well.
I basically do #2, but I also subtract 10 seconds off of the expires_in just to be certain I don't have a request made with a just-expired token. TBH there's no reason that Google would revoke an individual token that wouldn't result in full revocation of all access, that's kind of why their token lifetime is so short to begin with.
I don't use the official API client, but the Cliff's Notes version of my logic is:
class Token {
public function __construct($info) {
$this->token = $info['access_token'];
$this->type = $info['token_type'];
$this->expiry = time() + $info['expires_in'] - 10;
}
public function isValid() {
return ($this->validFor()) > 0;
}
public function validFor() {
return $this->expiry - time();
}
}
class TokenFactory implements TokenFactoryInterface {
public function token($force_new=false) {
if( $force_new || !isset($this->token) || !$this->token->isValid() ) {
$this->token = $this->newToken();
}
return $this->token;
}
}

Message: ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context

We're getting the exact same error as in this thread ... in our production environment.
[WIF Security Token Caching
Does anybody have a fix to this error ?
Message: ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context.
Here is some info about our setup:
• We‘re using built-in Windows Identity Framework with .NET Framework 4.5.1
• The problem is almost always associated with changing from RelyingParty#X over to RelyingParty#Y ( e.g. the moment user clicks the RP#Y he‘s SIGNED OUT without asking for it ) – when he logs in again after this event, he‘s taken right to the page he was asking for, inside RP#Y
• We‘re using e.SessionToken.IsReferenceMode = true; // Cache on server, to get a smaller cookie
• By using IsReferenceMode = true, our FedAuth cookie stores a „pointer“ to the actual Token which is stored inside our database
• We‘re using our own DatabaseSecurityTokenCache which is overriding the functions in SessionSecurityTokenCache. By using the the DatabaseSecurityTokenCache alongside the IsSessionMode = true, we‘re server-farm-friendly ( but we‘re also guaranteed to be within the same server through all our login-session ) so if the application pool for some reason dies, we‘re able to get the token from database through the DatabaseSecurityTokenCache. I‘ve verified this by completely killing IIS in the middle of a session ( with „net stop WAS“ and the restart it again with „net start W3SVC“ and we‘re still able to get the Token from the DatabaseSecurityTokenCache ). I‘ve also tried doing the same by simply using the out-of-the-box SessionSecurityTokenCache and that will fail respectivly ( as expected )
• Default token lifetime is 20 minutes ( but the user can change it to 40 or 60 minutes if he wants to ) – that will only be effective the next time the user logs in ( and 90% of our user are just using the default 20 minutes lifetime )
• We‘re using a certificate (same on all servers) to encrypt the FedAuth cookie, NOT a machine-key ( which would be catastrophic if using server-farm, with different machine-keys )
• so all the servers can decrypt cookies, which were encrypted from another server.
• We have a javascript with a countdown in our RelyingParty4 and RelyingParty5 ( two different relying parties ) which is used as a „timeout script“ in case the user leaves his computer unattended ... he will be signed out when the token is about to expire – (minus) 30 seconds ( e.g. 20 minutes – 30 sec = 19,5 minutes ) with idle time. This is protect our very sensitive banking information, so when the user comes back to his machine he will need to login again. e.g. We‘re also using sliding sessions ([http://www.cloudidentity.com/blog/2013/05/08/sliding-sessions-for-wif-4-5/]) and when we slide, the timing in the javascript of the client is also updated as well, to match the length of the token minus 30 seconds. These 30 seconds are used to make sure that the session is still alive when signing out, so it‘s a little bit shorter than the lifetime of the token/session. We currently sliding if this condition is met: total lifetime / 2 .... e.g. 20 / 2
• We‘re only sliding if there‘s any activity going on with the user ( i.e. he‘s moving around, doing some work ). We're sliding in minute10+ (if token lifetime is 20minuts) as the example above shows
• We‘ve debugged the problem multiple times and this is the WIF error we‘re getting: Exception: System.IdentityModel.Tokens.SecurityTokenException Message: ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context. Source: Microsoft.IdentityModel at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) at Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) at Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) at Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
• We‘ve been able to re-produce the bug by using an old FedAuth cookie and this plugin: ( attention! We‘re not sure if this is the same thing that‘s happening on PROD, but at least it gives the same error in our Logging system ) This is good, but I think you should add the steps on how we‘re able to modify the content of the FedAuth cookie, to bring this problem to life, locally.- You can use this:
It‘s simple by taking the Value of the FedAuth cookie from some previous sessions ( on the same machine! not from another machine, that won‘t work ) And pasting it into the Value of the FedAuth cookie and refreshing the page.-
Plugin used to modify the cookie, in Chrome is called „Edit This Cookie“:
- If we change the content of this cookie to a value from a previous session, and hit the refresh ( CTRL + R in Chrome ) we get the infamous TokenSecurityException ID4243 and the RP calls for a immidiate FederatedSignout because we're unable to recover from this situation.
Signing out....
I should also probably mention that we took's Microsoft MSDN's article marked "Important" on IsReferenceMode seriously and added it also to our
SessionAuthenticationModule_SessionSecurityTokenCreated event:
e.SessionToken.IsReferenceMode = true;
taken from MSDN:
Important!
To operate in reference mode, Microsoft recommends providing a handler for the WSFederationAuthenticationModule.SessionSecurityTokenCreated event in the global.asax.cs file and setting the SessionSecurityToken.IsReferenceMode property on the token passed in the SessionSecurityTokenCreatedEventArgs.SessionToken property. This will ensure that the session token operates in reference mode for every request and is favored over merely setting the SessionAuthenticationModule.IsReferenceMode property on the Session Authentication Module.
Below is our whole SessionAuthenticationModule_SessionSecurityTokenReceived,
please examine the comments I put into it ... it explains what everything does:
void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
{
if (e.SessionToken.ClaimsPrincipal != null)
{
DateTime now = DateTime.UtcNow;
DateTime validTo = e.SessionToken.ValidTo;
DateTime validFrom = e.SessionToken.ValidFrom;
TimeSpan lifespan = new TimeSpan(validTo.Ticks - validFrom.Ticks);
double keyEffectiveLifespan = new TimeSpan(e.SessionToken.KeyExpirationTime.Ticks - e.SessionToken.KeyEffectiveTime.Ticks).TotalMinutes;
double halfSpan = lifespan.TotalMinutes / 2;
if (validFrom.AddMinutes(halfSpan) < now && now < validTo)
{
SessionAuthenticationModule sam = sender as SessionAuthenticationModule;
// This will ensure a re-issue of the token, with an extended lifetime, ie "slide". Id deletes the current token from our databasetoken cache (with overriden Remove of the SessionSecurityTokenCache ) and writes a new one into the cache with the overriden AddOrUpdate of the SessionSecurityTokenCache.
// it will also write the token back into the cookie ( just the pointer to the cookie, because it's stored in database-cache ) because the IsReferenceMode = True is set
e.ReissueCookie = true; // Will force the DatabaseSecurityTokenCache'ið to clean up the cache with this, handler.Configuration.Caches.SessionSecurityTokenCache.Remove(key); internally in WIF's SessioAuthenticationModule
e.SessionToken = sam.CreateSessionSecurityToken(
e.SessionToken.ClaimsPrincipal,
e.SessionToken.Context,
now,
now.AddMinutes(lifespan.TotalMinutes),
false); // Make persistent, þannig að kakan lifir EKKI af browser-close / tab-lokun:
{
e.SessionToken.IsReferenceMode = true; // Cache on server
}
// Not needed, because if ReissueCookie = true; is set, it WILL to a WriteSessionTokenToCookie internally in WIF
//FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(e.SessionToken); // <---- er þetta e.t.v. bara það sem við þurfum ? Nei, á ekki að þurfa, er gert þegar tóki er búinn til með CreateSessionSecurityToken
}
else if (validTo < now)
{
// Fix
// http://blogs.planbsoftware.co.nz/?p=521
var sessionAuthenticationModule = (SessionAuthenticationModule)sender;
sessionAuthenticationModule.DeleteSessionTokenCookie(); // <--- is this really needed like the article says ? http://blogs.planbsoftware.co.nz/?p=521
e.Cancel = true; // This will allow a silent-login if the STS cookie is still valid, e.g. switching between RP's where we're switching from an active RP to a RP which has it's cookie outdated, but the STS's session is still alive. We don't want to prompt the user for a new login, beucase the STS session is still OK!
}
}
this post helped me, so it can help you and others those have this kind of error.
void Application_OnError()
{
var ex = Context.Error;
if (ex is SecurityTokenException){
Context.ClearError();
if (FederatedAuthentication.SessionAuthenticationModule != null){
FederatedAuthentication.SessionAuthenticationModule.SignOut();
}
Response.Redirect("~/");
}
}
From this link.
Hope it was useful!
---------- UPDATE, This is how Lord02 fixed the proplem -----------
The problem was that when users are coming in with stale cookies ( from a previous session, i.e. if they did NOT sign out from our system ... but instead just closed the tab ) and then logged in again,
our cookie which was in SessionMode = true ... tried to go to the DatabaseTokenCache to GET the whole token from database, but as I said our SSIS process deletes all Tokens which are OLDER than 12 hours old (outdated tokens!) so we don't have loads of orphan tokens, which are outdated in our database and are unusuable ... just taking up space in our database.
So after this deletion is done, each night, the DatabaseTokenCache GET‘s function would not return a valid Token ... and the user was signed out because of : ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context.
So instead of NOT deleting the Tokens inside our database I created a special handler, which intercepts this error on the RP‘s site ... and redirects the user back to the STS – which will then Create a brand new token and Write that down to the DatabaseTokenCacheStore, like this below
The exception with ID4243 is thrown when the cookie is set as “reference mode” AND the token is not present in the cache –
I can confirm that is by-design and also by-design WIF does not redirect the call to the STS (to start over the authentication process)
To overcome this problem I intercept this exception and react properly.
I redirect to the issuer if this error comes up inside a customSessionAuthModule I created for this:
public class CustomSessionAuthenticationModule : SessionAuthenticationModule
{
protected override void OnAuthenticateRequest(object sender, EventArgs eventArgs)
{
try
{
base.OnAuthenticateRequest(sender, eventArgs);
}
catch (SecurityTokenException exc)
{
// ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context.
if (exc.Message.IndexOf("ID4243", StringComparison.OrdinalIgnoreCase) >= 0)
{
// Returning directly without setting any token will cause the FederationAuthenticationModule
// to redirect back to the token issuer.
return;
}
else
{
throw;
}
}
}
}

Persistent cookie expiry set to Session in asp.net mvc?

I am using ASP.NET MVC and want to be able to automatically log somebody in when they return to the site (in exactly same way that this site does).
When a user first registers or logs in I set the cookie as follows:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
"playerid",
DateTime.Now,
DateTime.Now.AddMinutes(1), //This will be set to a longer period in live...
true,
Username + "|" + item.PlayerID.ToString(),
FormsAuthentication.FormsCookiePath);
string encTicket = FormsAuthentication.Encrypt(ticket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
If I test this by logging in as a user and then look at the Cookies tab in Firebug then the expiration is set to Session. If I close the browser and then go back to my site I am no longer logged in. This is what I'd expect as the session ends when the browser is closed (but it is not what I want to happen!).
However, if I log in and navigate about the site, then after a minute elapses the expiry no longer shows as Session but appears as an actual date stamp. If I then close the browser and go back to my site I am auto logged in.
In summary, it seems as if my expiration is set to Session until the actual expiry date I have stipulated passes (t + 1 min in this case) and I have been active on the site (I am using sliding expiration).
Any ideas how I can have my expiration set to what I am stating in the FormsAuthentication ticket (and not show as Session)?
You should create a persistent cookie that is stored on the client harddrive by setting the Expires property:
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
{
// setting the Expires property to the same value in the future
// as the forms authentication ticket validity
Expires = ticket.Expiration
};
Response.Cookies.Add(cookie);
Make sure that you have specified the same expiration timeout for the cookie and the forms authentication ticket. Now when you look with FireBug you will see that the when the cookie is emitted the Expires property is being set in the future which will make the cookie persistent and survive browser restarts:
Set-Cookie: ASPXAUTH=...; Expires=Tue, 15-Jan-2014 21:47:38 GMT; Path=/; HttpOnly

Handle session expire in MVC 2 with ajax

I want to check the session expired or not.
SO what i decided is Create an action called IsServerExpired and have it return a json object containing a boolean value, and the redirect url.
SO the java script function will do an ajax request to this action with specified time interval ..
I have some basic questions ..
1.If i send an ajax request ,i think that will refresh the session time . So in effect the session will not expire if i am using this method. am i right ?
If it refreshes how can i check session expire using polling
There is more simple approach to log out user once session expired.
You can save SessionTimeout somewhere on the client side and run client side timer, once timer reach end redirect user to log out url.
Here is example. Model here containts SessionTimeout value.
$(document).ready(function () {
var timeOutInMinutes = #Model;
if(timeOutInMinutes > 0)
{
setTimeout(function() {
window.location =
'#Url.Action("Logout", "Authentication", new {area=""})';
},timeOutInMinutes * 1000 * 60);
}
});
More user friendly way is to show popup that will say that session will be expired wihtin one minute(if session timeout 15 mins then show it after 14 mins), so user will be able refresh page. and continue work.
I think you are confusing between an ASP.NET session and the authentication cookie. I suspect that you are talking about the authentication cookie expiration here. If you have set slidingExpiration to true in your web.config then polling AJAX requests will renew the timeout so they are not suitable. Phil Haack described a very elegant way to detect authentication cookie expiration in AJAX calls in this blog post.

Resources