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.