I'm trying to get a subdomain to create a cookie for the entire domain instead of just its subdomian using the property cookie.domain, so the two subdomains can share the cookie info. When I deploy to IIS I get 2 cookies created, one for the domain and another for the subdomain. Why is that? When I update the cookie the only one that gets updated is the subdomain one, rendering the domain cookie kind of useless.
I tried to trace this through my code, but running visual studio in debug mode doesn't actually set any cookie at all, unless I don't set the cookie.domain property. Leaving domain.cookie out I get a cookie set to localhost, but only that one cookie. Any thoughts?
Okay, so I finally answered my own quesion(s). I'll tackle the second one first, about running the site in debug mode:
Visual studio debugs to the site http://localhost:[someport]. So if the code is set to create a cookie using cookie.domain for mydomain.com, the cookie isn't set because the browser knows you're at localhost instead of the domain specified. To remedy this I put an entry in my hosts file so that mydomain.com is pointed to 127.0.0.1. Then I fired up the site in debug mode. When the site came up as localhost I changed the URL in the browswer to http://subdomain.domain.com:[someport] and refreshed. Now the cookie can be set.
Doing this helped me trace through my code to find the issue of two cookies being created by my subdomain website. What I found is that the mydomain.com cookie was being created okay (CreateCookie method below) because of cookie.domain. However, when I was trying to update the expiration on the cookie (UpdateCookie below) it reverted back to thinking it should be using the subdomain cookie and went ahead and created it when it didn't find one. All I had to do was set cookie.domain again before setting the cookie and updating the expiration. Now I only have one cookie.
public void CreateCookie()
{
HttpCookie cookie = new HttpCookie(mConfig.webCookie);
TimeSpan span = new TimeSpan(0, 0, 30, 0);
DateTime time = DateTime.Now; ;
cookie["Username"] = mEncrypt.Encrypt(mUser.Username);
cookie.Domain = "mydomian.com";
cookie.Expires = time + span;
HttpContext.Current.Response.Cookies.Add(cookie);
}
public void UpdateCookie()
{
TimeSpan span = new TimeSpan(0, 0, 30, 0);
DateTime time = DateTime.Now;
HttpCookie cookie = HttpContext.Current.Request.Cookies[mConfig.webCookie];
// without specifying the domain the cookie will be set with the subdomain
cookie.Domain = "mydomain.com";
HttpContext.Current.Response.Cookies.Set(cookie);
HttpContext.Current.Response.Cookies[mConfig.webCookie].Expires = time + span;
}
You can set this cookie name for the full domain and subdomain on web.config on httpCookies
<httpCookies domain="domain.com" httpOnlyCookies="false" requireSSL="false" />
set domain.com and NOT www.domain.com to archive what you say, to have the same cookie on domain and sub domain. Similar there is a parameter on authentication that you set this cookie settings, depend for what cookie you talking about.
In your question "why is that?" the answer is that if you not set this parameters for the cookies then the cookies actually use the current host name, so they are different if the first name of the sub-domain change.
Related
I have two login pages. One for admin users and one for customers.
They both execute the below code (after authorisation) to add a cookie to the Response. The two pages then redirect to the URL provided (I don't do the redirect here as I do some extra checks on admin)
public static string SetAuthCookie<T>
(this HttpResponse responseBase, string name, bool rememberMe, T userData)
{
/// In order to pickup the settings from config, we create a default cookie
/// and use its values to create a new one.
var cookie = FormsAuthentication.GetAuthCookie(name, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var newTicket = new FormsAuthenticationTicket(
ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
true,
Newtonsoft.Json.JsonConvert.SerializeObject(userData),
ticket.CookiePath
);
var encTicket = FormsAuthentication.Encrypt(newTicket);
/// Use existing cookie. Could create new one but would have to copy settings over...
cookie.Expires = (rememberMe ? DateTime.Now.AddDays(62) : DateTime.MinValue);
cookie.Value = encTicket;
responseBase.Cookies.Set(cookie);
return FormsAuthentication.GetRedirectUrl(name, true /*This Is Ignored*/);
}
Admin
Now the admin does as it's told. Adds the cookie and redirects to an admin welcome screen.
Customer
The customer login area just isn't doing the same (see below screengrab).
It posts (as you can see it receives the request to save the cookie)
It redirects
But, oh no, the next request has no cookie
The system can't see the user is authenticated
Back to the login screen we go
I thought that the problem may be a local browser.
Nope, tried: different browsers, using private/incognito.
I thought it might be the setting of the cookie.
How can it be? They both use the same code.
Maybe web.config (in their respected directories)?
Nope, just <authorization> rules
Maybe a problem with the cookie?
Nope, looks fine. Same domain, HTTPS. all fine
Something to do with RememberMe?
Nope, tried both with and without
Soooo.... Been silly.
I forgot to exclude ([JsonIgnore]) a property that fetches some extra data (not needed for setting the cookie). This was being included and, obviously, made my cookie too large to save.
Oops.
How to delete cookies in ASP.NET after changing machine key but staying on the same sub-domain?
Currently we have cookies on example.domain.com, but we need to move to wildcard cookies (.domain.com) so that the cookie also work on foo.domain.com. In order to do this, we have manually set a machine key to encrypt/decrypt the asp.net login cookie. Problem is that people that already have the old cookie, will now receive a CryptographicException when trying to access the site (as it tries for some reason to decrypt the old cookie). We have changed the name of the cookie, but it did not help - still receives the error. So we figured out that we wanted to delete all the old cookies. We try do do this on the login site with the following code:
var myCookies = Request.Cookies.AllKeys;
foreach (var cookieName in myCookies)
{
var cookie = Request.Cookies[cookieName];
if (cookie == null) continue;
cookie.Value = "written " + DateTime.Now;
cookie.Expires = DateTime.Now.AddYears(-1);
cookie.Domain = "example.domain.com"
Response.Cookies.Add(cookie);
}
We reach the code, and it runs, but the cookies still remain when inspecting in google chrome resources. So obviously the deletion did not work. We have tried several different ways (adding path ="/", setting cookie.Value to cookie.Value etc. For some strange reason the cookies still remain and we are unavailable to delete them.
So to get back to the original question, how an we delete cookies in ASP.NET MVC 4.5 after changing to a wildcard domain on our cookies and explcitly stating the machine key in the web.config?
If you don't absolutely have to use the same ticket name, your solution should work if you changed the name of the FormsAuthentication cookie:
<forms name=".YOUR_NEW_COOKIE_NAME" /> **
** Note that I've omitted the other attributes from the tag shown, so you wouldn't want to copy/paste it verbatim.
Turns out that by removing cookie.Domain, it managed to delete the cookies. I recon this has to do with the fact that in order to overwrite a cookie, you need to be as specific as possible when adding the replacing cookies. Seeing as the former cookies was added without specifying domain nor path, this is the most specific.
The code that ended up working in this scenario, was therefor:
var myCookies = Request.Cookies.AllKeys;
foreach (var cookieName in myCookies)
{
var cookie = Request.Cookies[cookieName];
if (cookie == null) continue;
cookie.Value = "written " + DateTime.Now;
cookie.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie);
}
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.
consider this, If one is user of a Web application
like :
A someone visits SomeWebSite.com as a normal User (registered)
HttpCookie cookie = new HttpCookie("LastVisit");
cookie.Value = DateTime.Now.ToString();
cookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cookie);
B visits SomeWebSite.com, using another account as a moderator / admin
HttpCookie cookie = new HttpCookie("LastVisit");
cookie.Value = DateTime.Now.ToString();
cookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cookie);
Both cookies belong to same domain, but for two different Accounts. How does browser know Which cookie belongs to which account ? if we use the following code to access it.
if (Request.Cookies["LastVisit"] != null)
{
string lastTimeUserVisited = Request.Cookies["LastVisit"].Value;
}
EDIT: It's my first time ever to work on cookies.
I do appreciate your patience
I don't quite understand the question. A single browsing session won't distinguish between the two cookies. The last cookie that the server sets replaces the previous ones. Obviously, two instances of Chrome running on two different computers don't share cookies and each send their own instance of the cookie to the server in every request.
How does browser know Which cookie
belongs to which account?
It doesn't. The cookie for the second visit overwrites the cookie for the first. If you want that to be different, you have to use different cookie names, e.g. by appending the user ID to the cookie name.
If the users are logged in using the same user account on the computer, they will be using the same set of cookies.
If they are logged in using separate user accounts, they will each have their own set of user folders and thus their own browser settings and their own set of cookies.
Client has a site at a.url.com. Client creates a cookie with host as ".url.com" and path as "/". Client redirects to us at b.url.com. Client has a coding issue that requires us to delete the cookie (long story).
The following code is not adjusting the expiration at all in our test or production environments but is working fine locally.
if (Request.Cookies["cookie"] != null)
{
HttpCookie myCookie = new HttpCookie("cookie");
myCookie.Expires = DateTime.Now.AddDays(-1d);
Response.Cookies.Add(myCookie);
}
Any ideas?
We've figured it out. We needed to add one line of code to manually set the domain. Makes total sense now.
if (Request.Cookies["cookie"] != null)
{
HttpCookie myCookie = new HttpCookie("cookie");
myCookie.Domain = ".url.com";
myCookie.Expires = DateTime.Now.AddDays(-1d);
Response.Cookies.Add(myCookie);
}
is this a third party cookie? If so, the default security settings in IE will prevent cookie writing in the "internet" zone but it is allowed in your local zone.
Here's a hack. I am just posting this in case you find out that you cannot do what you want due to some security issue preventing you handling the issue on the second site.
You could send a request to the first site to clear the cookie via redirect and have that site bounce the user back again. Like I said, this is very hackish (or I suppose marketing would call it inter-site cooperative security feature).
Hopefully, there's a better approach, but at least you have an alternative if no other ones are forthcoming.
If you cannot get it working in C# you might want to consider seeing if you can manipulate the cookies in javascript.
Gary