Saturday, December 29, 2007

ASP.NET and subdomains

One of the features of the application I've been working on for a past few months is an option to create subdomains for our users where we host their profiles. If you don't know what I'm talking about, take a look at my blog address (http://mgrzyb.blogspot.com). That's exactly what we want.

It seemed easy to implement. First we created a wildcard entry in our DNS pointing to our server. This ensured that any request to a subdomain would be send to our application. We thought all that was left was parsing out a user name from the host and tada! We were wrong.

The first problem showed up when logging in using forms authentication. It appeared that the cookie created by FormsAuthentication.SetAuthCookie by default creates a cookie with a Domain property set to the current domain. The thing is that the domain was changing then we redirected users from the root domain to their subdomain. So for example a user would authenticate on myapp.com and be redirected to mgrzyb.myapp.com upon successful login. Authentication cookie domain would be myapp.com, so it would not be valid for the request to mgrzyb.myapp.com and the request would not be authenticated.

This one was easy to solve. All you need to know is that for a cookie to be valid in all subdomains of myapp.com the domain must be set to ".myapp.com" (note the extra dot) (also see: http://webmaster.info.aol.com/aboutcookies.html) and that authentication cookie domain can be set in web.config.

The second problem was not that obvious and not that easy to solve. Some of you might have already guessed that we hit the same cookie domain problem again but this time it was a session id cookie. We don't use session intensively in the application so initially we did not notice that ASP.NET maintained separate sessions for every subdomain a user would browse to. I thought to myself, phew, we'll just change the session cookie domain in web.config file and its done. Wrong! There is no config option to set the domain of the session cookie.

Using Reflector I discovered that the cookie is created by SessionIDManager class implementing ISessionIDManager interface. What if we could create our own ISessionIdManager implementation that would create a cookie with a domain we like? We can. SessionState element of web.config file allows us to specify a type of the ISessionIDManager that SessionStateModule will use.

To avoid reimplementation of the whole class one would like to use System.Web.SessionState.SessionIDManager as a base class but the SaveSessionID method is not virtual so cannot be overridden. Options are: either explicitly re-implement the interface method or decorate SessionIDManager class and after calling SessionIDManager.SaveSessionID set Response.Cookies[SessionIdCookieName].Domain to our domain.

It worked! Now our application supports cross subdomain authentication and sessions.

5 comments:

Mauricio Sola said...

Hi Maciej !!!
I'm contacting you from Argentina, South America. I hope you receive this message. I don't know how long this message could be, so, I'll try to be clear in my explanation.
I was surfing for the net for 3 days along looking for some good information about managing subdomains with ASP.NET, I found your post, and I became happy because I realize you had a similar issue as I have now. Let me explain that.
I'm programming a website that has a similar behavior as the site you were working on. So, I'd like to know the way you manage some issues, such as:

* Issues related with parsing the url and redirecting to another url that manages the data for an specific user (if we need this).
* So, do I need just only one app (located into, for example, myapp.com), for managing all users requests? This is my goal for this application.
* Do I need a DNS service for redirecting all requests from *.myapp.com to myapp.com?
I'd like just only know the strategy you use for solving this issues (a little bit of code could be helpful too :D ).

Well, I hope you can help me with this. You can reach me at maurijdeer@yahoo.com.ar, and we can talk a little bit more about this, without posting all messages into your blog!
Many thanks in advance !

Maciek said...

Hi Mauricio,
I tried to address you questions here: http://mgrzyb.blogspot.com/2008/09/aspnet-and-subdomains-reloaded.html

Hope this helps.

nash said...

you said:
"either explicitly re-implement the interface method or decorate SessionIDManager class and after calling SessionIDManager.SaveSessionID set Response.Cookies[SessionIdCookieName].Domain to our domain."

Could you please present the exact code you wrote, not just description

Rodrigo said...

>Use this on your web.config, it works well for me.

Rodrigo said...

httpCookies domain=".yourdomain.com" httpOnlyCookies="true" requireSSL="false"