I've noticed that there are some real inconsistencies between browsers in terms of cookies.
This is going to be rather long so bear with me.
Note: I've setup a domain in my host file called "testdomain.com", this bug WONT work when using "localhost".
Note2: I am curious to know how this works on Apache/PHP if when you retrieve a cookie by name if it gives a collection of cookies back.
Wikipedia
Wikipedia states that: http://en.wikipedia.org/wiki/HTTP_cookie#Domain_and_Path
Domain and Path
The cookie domain and path define the scope of the
cookie—they tell the browser that cookies should only be sent back to
the server for the given domain and path. If not specified, they
default to the domain and path of the object that was requested.
So if we push down:
Response.Cookies.Add(new HttpCookie("Banana", "2")
{
});
We should get a cookie with the domain used being the domain from the requested object, in this case it should be "testdomain.com".
W3
W3 states in the specification for cookies: http://www.w3.org/Protocols/rfc2109/rfc2109
Domain=domain
Optional. The Domain attribute specifies the domain for which the
cookie is valid. An explicitly specified domain must always start
with a dot.
So if we push down:
Response.Cookies.Add(new HttpCookie("Banana", "1")
{
Domain = Request.Url.Host
});
We pushed down the host-name explicitly, we should get a domain name set on the cookie which would be prefixed with the dot, in this case it should be ".testdomain.com".
It also states what's on Wikipedia:
Domain Defaults to the request-host. (Note that there is no dot at
the beginning of request-host.)
With me so far?
If I use the first method, defining a Domain:
Response.Cookies.Add(new HttpCookie("Banana", "1")
{
Domain = Request.Url.Host
});
This is the results:
IE9: 1 cookie
Opera: 1 cookie
Firefox: 1 cookie
Chrome: 1 cookie
As you can see, both Opera and IE both set an EXPLICIT domain without the dot prefix.
Both Firefox and Chrome DO set the EXPLICIT domain with a dot prefix.
If I use the following code:
Response.Cookies.Add(new HttpCookie("Banana", "2")
{
});
IE / Opera: Both have the exact same result, the domain WITHOUT the dot prefix.
Funnily enough, Firefox and Chrome both create cookies WITHOUT the dot prefix.
(I cleared all cookies and ran the code again)
Firefox:
Chrome:
INTERESTING BIT
This is where it gets interesting. If I write the cookies one after another like so:
Response.Cookies.Add(new HttpCookie("Banana", "1")
{
Domain = Request.Url.Host
});
Response.Cookies.Add(new HttpCookie("Banana", "2")
{
});
PERSONALLY I would expect one cookie to exist in the browser, because I assume it's based on the cookie name.
Here's what i've observed:
In IE / Opera, the LAST cookie set is the cookie that is used. This is because the Cookie name and Domain name are identical.
If you explicitly define a domain name with a dot, both browser will still see 1 cookie, the last cookie of the same name.
Chrome and Firefox on the other hand, see more than 1 cookie:
I wrote the following JavaScript to dump the values to the page:
<script type="text/javascript">
(function () {
var cookies = document.cookie.split(';');
var output = "";
for (var i = 0; i < cookies.length; i++) {
output += "<li>Name " + cookies[i].split('=')[0];
output += " - Value " + cookies[i].split('=')[1] + "</li>";
}
document.write("<ul>" + output + "</ul>");
})();
</script>
These are the results:
IE - 2 cookies set (browser sees 1):
Opera - 2 cookies set (browser sees 1):
Firefox - 2 cookies set and browser sees 2!:
Chrome - 2 cookies set and browser sees 2!:
Now you're probably wondering wtf all this is.
Well:
When you access the cookie by Name in C#, it gives you 1 cookie. (the first cookie that has that name)
The browser sends ALL cookies to the server
The browser doesn't send any information other than the key/value of the cookie. (this means the server doesn't care about the domain)
You can access both cookies of the same name, if you retrieve them by index
The problem...
We had to change our Authentication to specify the domain in the cookie when we pushed it down.
This broke Chrome and Firefox, users were no longer able to login, because the server would try authenticate the old auth cookie. This is because (from my understanding) it uses the Authentication Cookie Name to retrieve the cookie.
Even tho there are two cookies, the first one is retrieved which happens to be the old one, authentication fails, user isn't logged in. SOMETIMES the correct cookie is first in the list, and the authentication succeeds...
Initially we solved this by pushing a cookie with the old domain to expire it. This worked in Chrome and Firefox.
But it now broke IE/Opera since both browsers don't care about the domain and only compare the cookie based on the name.
My conclusion is that the domain on a cookie is a complete utter waste of time.
Assuming that we must specify the domain, and we can't rely on users to clear their browser cache. How can we resolve this problem?
Update:
Digging into how .NET signs a user out.
if (FormsAuthentication._CookieDomain != null)
{
httpCookie.Domain = FormsAuthentication._CookieDomain;
}
It looks like it's entirely possible for the Forms authentication to push an expired Auth cookie, that is entirely unrelated to the cookie the user is authenticated with. It doesn't use the current Auth Cookie's domain.
Which it can't use anyway, since the domain isn't pushed back to the server with the cookie.
Update 2
It seems FormsAuthentication is really broken. If you use an explicit domain name on a cookie when you authenticate the user, wait for the session to timeout, then refresh the page, the method of generating the cookie used by FormsAuthentication results in the domain being null which causes the browser to assign a dotless domain.
It requires that Forms be assigned a domain up front for it to be assigned to the cookie, this breaks a multi-tenant system...
#WilliamBZA's suggestion helped solve the initial problem, but then signout/session timeout bug that results in the cookie creating an implicit domain cookie has made me come to the conclusion that the solution is...
Don't use Explicit cookies in .NET... ever
There are far too many problems, sure they can be solved by being explicit on the Form/Domain, Cookie/Domain, etc. To ensure that the correct domain is used everywhere. But if your application hosts multiple domains or is multi tenant, then it just becomes too problematic.
Lesson is learnt. Don't use explicit cookies.
Can't help with why the cookies are treated differently, but a quick fix would be to use a different cookie name per sub-application rather than using the domain of the cookie.
In the case of Forms Authentication, change the name of the ASPXAUTH cookie.
Related
I am using OWIN Authentication for a Multi-Tenant ASP.NET MVC application.
The application and authentication sits on one server in a single application but can be accessed via many domains and subdomains. For instance:
www.domain.com
site1.domain.com
site2.domain.com
site3.domain.com
www.differentdomain.com
site4.differentdomain.com
site5.differentdomain.com
site6.differentdomain.com
I would like to allow a user to login on any of these domains and have their authentication cookie work regardless of which domain is used to access the application.
This is how I have my authentication setup:
public void ConfigureAuthentication(IAppBuilder Application)
{
Application.CreatePerOwinContext<RepositoryManager>((x, y) => new RepositoryManager(new SiteDatabase(), x, y));
Application.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieName = "sso.domain.com",
CookieDomain = ".domain.com",
LoginPath = new PathString("/login"),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager, User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateClaimsAsync(manager),
getUserIdCallback: (claim) => int.Parse(claim.GetUserId()))
}
});
Application.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
I have also explicitly set a Machine Key for my application in the root web.config of my application:
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey="<Redacted>" validation="<Redacted>" validationKey="<Redacted>" />
</system.web>
</configuration>
Update
This setup works as expected when I navigate between domain.com and site1.domain.com, but now it is not letting me login to differentdomain.com.
I understand that cookies are tied to a single domain. But what is the easiest way of persisting a login across multiple domains? Is there a way for me to read a cookie from a different domain, decrypt it, and recreate a new cookie for the differentdomain.com?
Since you need something simple, consider this. In your particular setup, where you really have just one app accessible by multiple domain names, you can make simple "single sign on". First you have to choose single domain name which is responsible for initial authentication. Let's say that is auth.domain.com (remember it's just domain name - all your domains still point to single application). Then:
Suppose user is on domain1.com and you found he is not logged-in (no cookie). You direct him to auth.domain.com login page.
Suppose you are logged-in there already. You see that request came from domain1.com (via Referrer header, or you can pass domain explicitly). You verify that is your trusted domain (important), and generate auth token like this:
var token = FormsAuthentication.Encrypt(
new FormsAuthenticationTicket(1, "username", DateTime.Now, DateTime.Now.AddHours(8), true, "some relevant data"));
If you do not use forms authentication - just protect some data with machine key:
var myTicket = new MyTicket()
{
Username = "username",
Issued = DateTime.Now,
Expires = DateTime.Now.AddHours(8),
TicketExpires = DateTime.Now.AddMinutes(1)
};
using (var ms = new MemoryStream()) {
new BinaryFormatter().Serialize(ms, myTicket);
var token = Convert.ToBase64String(MachineKey.Protect(ms.ToArray(), "auth"));
}
So basically you generate your token in the same way asp.net does. Since your sites are all in the same app - no need to bother about different machine keys.
You redirect user back to domain1.com, passing encrypted token in query string. See here for example about security implications of this. Of course I suppose you use https, otherwise no setup (be it "single sign on" or not) is secure anyway. This is in some ways similar to asp.net "cookieless" authentication.
On domain1.com you see that token and verify:
var ticket = FormsAuthentication.Decrypt(token);
var userName = ticket.Name;
var expires = ticket.Expiration;
Or with:
var unprotected = MachineKey.Unprotect(Convert.FromBase64String(token), "auth");
using (var ms = new MemoryStream(unprotected)) {
var ticket = (MyTicket) new BinaryFormatter().Deserialize(ms);
var user = ticket.Username;
}
You create cookie on domain1.com using information you received in token and redirect user back to the location he came from initially.
So there is a bunch of redirects but at least user have to type his password just once.
Update to answer your questions.
Yes if you find that user is authenticated on domain1.com you redirect to auth.domain.com. But after auth.domain.com redirects back with token - you create a cookie at domain1.com as usual and user becomes logged-in a domain1.com. So this redirect happens just once per user (just as with usual log in).
You can make request to auth.domain.com with javascript (XmlHttpRequest, or just jquery.get\post methods). But note you have to configure CORS to allow that (see here for example). What is CORS in short? When siteB is requested via javascript from siteA (another domain) - browser will first ask siteB if it trusts siteA to make such requests. It does so with adding special headers to request and it wants to see some special headers in response. Those headers you need to add to allow domain1.com to request auth.domain.com via javascript. When this is done - make such request from domain1.com javascript to auth.domain.com and if logged in - auth.domain.com will return you token as described above. Then make a query (again with javascript) to domain1.com with that token so that domain1.com can set a cookie in response. Now you are logged in at domain1.com with cookie and can continue.
Why we need all this at all, even if we have one application just reachable from different domains? Because browser does not know that and treats them completely different. In addition to that - http protocol is stateless and every request is not related to any other, so our server also needs confirmation that request A and B made by the same user, hence those tokens.
Yes, HttpServerUtility.UrlTokenEncode is perfectly fine to use here, even better than just Convert.ToBase64String, because you need to url encode it anyway (you pass it in query string). But if you will not pass token in query string (for example you would use javascript way above - you won't need to url encode it, so don't use HttpServerUtility.UrlTokenEncode in that case.
You are right on how cookie works, but that it not how OWIN works.
Don't override the cookie domain of the Auth Server(auth.domain.com).
You may override the cookie domain of the individual sites to "site1.domain.com" and "site2.domain.com".
In your SSO page, let's say someone lands on site1.domain.com and since is unauthenticated is taken to your auth server. The auth server takes the login credentials and sends a code to site1.domain.com on the registered URI(eg: /oauthcallback). This endpoint on site1.domain.com will get an access token from the code and SignIn(automatically write the cookie). So 2 cookies are written one on auth.domain.com and second on site1.domain.com
Now, same user visits site2.domain.com and finds a cookie of logged in user on "auth.domain.com". This means that the user is logged in and a new cookie is created with same claims on "site2.domain.com"
User is now logged into both site.
You don't manually write the cookie. Use OwinContext.Signin and the cookie will be saved / created.
To answer the question on your update, there is no way of sharing cookies across different domains.
You could possibly use some query strings parameters and some server side logic to handle this particular case, but this could raise some security concerns.
Se this suggestion: https://stackoverflow.com/a/315141/4567456
Update
Following your comment, here are the details:
https://blog.stackoverflow.com/2010/09/global-network-auto-login/
https://meta.stackexchange.com/questions/64260/how-does-sos-new-auto-login-feature-work
http://openid.net/specs/openid-connect-session-1_0.html
Bonus:
The mechanism in use today is a bit different, and simpler, than what is discribed in the first two links above.
If you look at the network requests when you login on StackOverflow, you will see that it logs you in individually to each site on the network.
https://stackexchange.com/users/login/universal.gif?authToken=....
https://serverfault.com/users/login/universal.gif?authToken=...
https://askubuntu.com/users/login/universal.gif?authToken=...
etc, etc...
William,
I understand that cookies are tied to a single domain.
Yes and there is no way you can manipulate it on the client side. The browsers never send a cookie of one domain to another.
But what is the easiest way of persisting a login across multiple domains?
External Identity Provider or Security Token Service (STS) is the easiest way to achieve this. In this setup all the domains site1.com. site2.com etc will trust the STS as the identity provider. In this federated solution, the user authenticates with the STS and the federated identity is used across all the domains. Here is a great resource on this topic from an expert.
Is there a way for me to read a cookie from a different domain, decrypt it, and recreate a new cookie for the differentdomain.com?
With some tweaks you may achieve this federated solution with your current setup. FYI, this is not recommended or an in-use approach, but an idea to help you achieve the goal.
Lets say you have multiple domains 1, 2, 3 pointing to a single application. I will create another domain STS pointing to the same application but deals only with cookie creation and validation. Create a custom middleware that utilizes the asp.net cookie authentication middleware under the wrap. This gets executed only if the requests are for STS domain. This can be achieved with a simple if condition on the domain/ host or by using the Map on IAppBuilder interface.
Lets look at the flow:
a. The user tries to access a protected resource using domain 1
b. Since he is not authenticated, he will be redirected to domain STS, with a query parameter for domain1 (for STS to identify which domain he is accessing the resource from) and the url for the protected resource on domain1
c. As the request is for STS domain, the custom middleware kicks in and authenticates the user. And sends two cookies one for STS and the second one for whatever the domain (in this case 1) he is trying.
d. Now the user will be redirected to the protected resource on domain1
e. If he tries to access protected resource on domain 2, he is not autheticated hence will be redirected to STS.
f. Since he had an authentication cookie for STS that will be attached with this request to STS by the browser. The STS middleware can validate the cookie and can authenticate the user. If authenticate, issues another cookie for domain 2 and redirects him to the protected resource on domain2.
If you closely look at the flow it is similar to what we do when we have an external STS, but in our case the STS is our application. I hope this makes sense.
If I had to do this task, I would use an external STS sitting on the same host (IIS). IdentityServer, an opensource implementation of OpenID Connect standard, is what I would use as STS. It is extremely flexible in terms of usage and can be co-hosted with our application (which I think is great deal in your case). Here are links Identity server, Video
I hope that this is helpful. Please let me know if you have any questions.
Thank you,
Soma.
I'm having some really weird cookie issues on a website. It's an ASP.NET website, uses Umbraco 6.1.6 as its CMS but is mainly custom code and uses Forms Authentication for user login. It runs on IIS Server 2012 R2.
On successful registration, the user credentials are passed to the login method, which sets a cookie like this:
var authTicket = new FormsAuthenticationTicket(realUsername, false, 60);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
Path = FormsAuthentication.FormsCookiePath,
Domain = FormsAuthentication.CookieDomain,
Expires = authTicket.Expiration
};
HttpContext.Current.Response.Cookies.Set(cookie);
It then does a redirect, trying to go to wherever the user was previously on the site before registering.
return Redirect(redirectUrl);
From the redirected page, it checks the request cookie to see whether the user was logged in:
HttpCookie authCookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
Sometimes the authCookie contains the session data, and works for long periods of time..... and other times it is null - for equally long periods of time - so it only intermittently works.
This led me to believe that perhaps IIS is having trouble checking the request cookie on redirect - because the cookie has not yet reached the user's browser. But various docs and other SO posts tell me this should work when I am using a ResponseRedirect type redirect.
The bit where it gets weird is that when I've just registered but the server thinks I'm not logged in, I can look at the cookies for this "not logged in" page in Chrome dev tools, and it's true - there's no cookie set - however, when you click on the site's "Login" button from the "not logged in" page... which forces it to check whether the user is logged in again, this time "authCookie" contains cookie data. Right after Chrome told me this data was not present when I submitted the page! The cookie then reappears in dev tools when the "logged in" page is returned.
At this point, I don't know whether it's that I can't trust Chrome dev tools, or it's that there's some odd browser caching / IIS caching going on, or what. I tried looking up cookie / redirection issues and they only seem to come up with newer versions of IE.
I've tried closing the browser, closing visual studio, and that doesn't seem to have a direct impact.
One last bit of information - I read in one post here that there are sometimes issues when the registration / login is performed on one thread but the code after registration is performed on another thread. I checked the thread debugger and found that indeed the registration / login were being performed on different threads... but this was observed when it was working.
The most frustrating part is when it suddenly starts working for a few hours - and there's seemingly nothing I can do to break it again to try out different things. (Which is where I am now! I wanted to at least try it in different browsers...)
I've got 2 MVC3 Internet websites. One (Site1) uses Windows authentication and is in the Local Intranet Zone. The second (Site2) is publicly available and uses Forms Authentication. Both sites are in the same Domain, but have a different sub-domain. I want to share authentication cookies between the two. In order to do this, they need identical settings in the web config. Sometimes this works, most of the time it doesn't. If anyone hits Site1 from outside our network, they get a 403 error, which is good. If a network user hits Site1, they're allowed in based on their network credentials. I then check their user's roles with the code below.
var userName = string.Empty;
var winId = (WindowsIdentity)HttpContext.User.Identity;
var winPrincipal = new WindowsPrincipal(winId);
if(winPrincipal.IsInRole("SiteAdmin")) {
FormsAuthentication.SetAuthCookie("siteadmin", false);
userName = "siteadmin"; //This is a Forms Auth user
}
else if(///I check for other roles here and assign like above)
Once I've checked the roles, I forward them onto Site2, creating a cookie for them if the user is in one of the roles determined in the if...statement above.
if(!string.IsNullOrEmpty(userName)) {
//Add a cookie that Site2 will use for Authentication
var cookie = FormsAuthentication.GetAuthCookie(userName, false);
cookie.Domain = FormsAuthentication.CookieDomain; //This may need to be changed to actually set the Domain to the Domain of the TVAP site.
HttpContext.Response.Cookies.Add(cookie);
}
//Network users not found in roles will simply be forwarded without a cookie and have to login
HttpContext.Response.RedirectPermanent(tvapUrl);
I've set up in the web.config a matching MachineKey (validationkey, decryptionkey and validation) for each site.
They also both have the same authentiation settings, with the exception of the mode. So my config for this looks like this.
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" name=".ASPXFORMSAUTH" protection="All" path="/" domain="mydomain.com" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
I think my problem is that the 'authentication' mode is different for each one, so Site2 won't use the authentication cookie from site1. This is just a guess though. Is there anyway I can figure out the issue?
According to this article, what I have going here should work. And there have been times where I think it's worked, but it's hard to tell, as I may have cookies cached and their getting reused. I'm hoping someone can see something I'm missing here, or has an alternative solution.
UPDATE
I checked my authentication cookie on Site2 after logging in normally and found the Domain wasn't set, so I've removed that line of code.
Also, I read about cookies expiring when the date isn't set, so I set an Expire Date on my cookie before sending with the request.
So, with those two changes, here's where I'm at.
It works on Chrome and Firefox, but not with IE. Not sure. I'm going to do some additional testing from another machine and another user so I know I haven't got any residual cookies sitting around.
I determined my problem was not setting the Expires property of my cookie. According this Microsoft article, cookies won't be written to the client unless the Expires property is set.
"If you do not set the cookie's expiration, the cookie is created but it is not stored on the user's hard disk. Instead, the cookie is maintained as part of the user's session information. When the user closes the browser, the cookie is discarded. A non-persistent cookie like this is useful for information that needs to be stored for only a short time or that for security reasons should not be written to disk on the client computer. For example, non-persistent cookies are useful if the user is working on a public computer, where you do not want to write the cookie to disk."
In this case, I needed the cookie to be written to disk since I was doing a server transfer to another site, thereby ending the session for that user. I'm not 100% sure that this was the fix, but it is working now, so I'm assuming that.
This has been a nagging issue for some time, but very sporadic and difficult to isolate.
From time to time, browsers that have authenticated on a web application, have been open for a while, have logged in and out of the same web application multiple times, have multiple tabs, are pretty much any browser (Chrome, IE, Firefox, Safari), and seemingly at random, lose their ability to retain an AuthCookie after being set and followed by a redirect. Closing the browser and starting a new session resolves the issue, as does opening up a different browser and attempting to authenticate.
Our team uses forms authentication for all of our websites and web application. This is a pretty typical setup where a login form is displayed, the user enters credentials and a cookie is set on the click event of the postback, then a redirect occurs to the same page where the cookie is then referenced and used to complete authentication.
In this situation
FormsAuthentication.FormsCookieName = ".WebAuth"
Within Event:
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, Username, DateTime.Now, DateTime.Now.AddMinutes(SessionTimeout), false, Username);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(authTicket));
Response.Cookies.Add(faCookie);
Response.Redirect(Request.RawUrl, true);
After the redirect, on PreInit:
HttpCookie authCookie = Request.Cookies[cookieName];
At this point, the authCookie variable is typically not null, but in these isolated circumstances that I've outlined above, the cookie comes back null after the redirect.
This happens very randomly, sometimes weeks before affecting one of our developers. As I said, restarting the browser resolves the issue.
Today I had it happen on our dev server while using Chrome. I had logged into the application, allowed the application to session timeout, and then attempted to login again. The attempted login then failed to set the cookie. I remotely attached Visual Studio to the process on the server to begin debugging. The entire time I could step through my code, even deploy new code versions to the server with updates, restart the app, restart IIS on the server, attach and reattach to the project, and the issue persisted in Chrome. In Firefox, I was able to authenticate without issue.
From Chrome, the login would validate, attempt to set a Response Cookie as outlined above. Prior to redirect, I could see the properly set Response Cookie, as well as its counterpart in the Request Cookies. However, on each redirect after a seemingly successful login, the Response and Request Cookie are gone.
I enabled Trace on the application to view the cookie collection:
There is a .WebAuth in the Request Cookies Collection, as well as ASP.NET_SessionId and several ASPSESSIONIDxxxxxxxx, but when the page loads, only the ASP.NET_SessionId and ASPSESSIONIDxxxxxxxx cookies are available in the Request.Cookies scope, no sign of the .WebAuth. However, in the page's Trace information after render, there multiple .WebAuth cookies listed, it is just that the page seems to have no access to them.
Primarily, on a working version after authentication there is both a .WebAuth Response and Request Cookie in the page's Trace info. But on a non functioning browser window, the Response Cookie is absent.
Has anyone else had any experience with this? It is such a nagging issue, and so sporadic, but I would love to be able to resolve it. My concern is that it may be affecting users and we would have no knowledge since the description of the issue is so convoluted.
Based on your scenario you may be running into browser's restrictions on number of cookies per domain/total. The limits are relatively high, but exist (spec: http://www.ietf.org/rfc/rfc2109.txt, section 6.3 , some recent information - http://www.nczonline.net/blog/2008/05/17/browser-cookie-restrictions/)
If you get it happening again try to look at actual server responses (i.e. using Fiddler) to see if cookies are send to the browser. Check what cookies are set for the domain and current page (depending on browser there are different ways of doing it, in all browsers you can see some cookies by running following in address bar javascript:alert(document.cookie) )
This is a non-persistent cookie issue. Session simply times out.
Try changing false to true in this line:
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, Username, DateTime.Now, DateTime.Now.AddMinutes(SessionTimeout), true, Username);
Also add
faCookie.Expires = DateTime.Now.AddMinutes(SessionTimeout);
I have fall in similar situation, things was certain as you described. But, later the reason have been found.
ASP.NET and IIS understood MyApplication and myapplication as one equal, but browsers undertood them as different. So, when we set auth cookies for /MyApplication, they were not sent to the server, when we go to /myapplication.
The fix is next:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string url = HttpContext.Current.Request.Url.PathAndQuery;
string application = HttpContext.Current.Request.ApplicationPath;
if (!url.StartsWith(application))
{
HttpContext.Current.Response.Redirect(application + url.Substring(application.Length));
Response.End();
return;
}
}
Q1
I’ve read that when setting the timeout of an authentication cookie, we should keep in mind that the longer the cookie persists, the greater the chance of a cookie being stolen and misused.
A) But assuming we secure our application against replay attacks by enabling SSL for the entire application, and since forms authentication module also encrypts authentication data in authentication cookie, then I would think there is no chance of this cookie being misused and thus cookies being persisted for longer periods of time should not present any security risks?!
Q2
FormsAuthentication.FormsCookiePath specifies where authentication cookie is stored. Default value is ‘/’.
A) Assuming default value ’/’ is used, where is cookie saved then?
B) Is this option only used for persistent cookies?
thanx
2A The cookie path is the path on the server the cookie relates to, not the path where the cookie is store.
From http://www.quirksmode.org/js/cookies.html
The path gives you the chance to specify a directory where the cookie is active. So if you want the cookie to be only sent to pages in the directory cgi-bin, set the path to /cgi-bin. Usually the path is set to /, which means the cookie is valid throughout the entire domain.
This script does so, so the cookies you can set on this page will be sent to any page in the www.quirksmode.org domain (though only this page has a script that searches for the cookies and does something with them).
You are using ASP.Net. Also see the "CookieLess" Session and Authenication options e.g.
http://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.formscookiepath.aspx If you are worried about cookies. This uses a URL session ID instead to track your session.
You can also use a SQL Server to track session state or a State server.
e.g.
<sessionState mode="SQLServer" sqlConnectionString="SQLSessionDB" cookieless="false" timeout="65" cookieName="MSESSID"/>
1A. SSL encrypts transport. Hence your cookies will be less likely to be stolen on route to the client or back. That doesn't mean a malicious program on the client computer can't steal it. This is very unlikely though.