Tuesday, January 24, 2012

Single sign on between a domain and a subdomain using forms authentication

I ran into an interesting situation on a site using forms authentication, where the user had to be logged into both a domain and its subdomain once authenticated. Here's what I had to do to get this to work.

Both sites being seperate applications in themselves the authentication cookies generated by asp.net would be different due the encryption keys used by the sites. The Auth cookie generate by domain.com cannot be read by subdomain.domain.com. To get over this issue we need to add a machine key element in the web.config's of the both the apps. This key is going to be the same in both apps.

There are several different options in setting up these keys. Read more about it in this page. It also includes some code on how to generate a machine key using a console app - http://msdn.microsoft.com/en-us/library/ff649308.aspx

Once this is taken care of, the next issue we are going to have is the cookie itself. When a cookie is created - it is domain specific, so a cookie created by a sub domain will not be accessible to its parent level domain. In my case, the user authentication was to be performed on a subdomain using MVC. So I had to generate cookies for both the sub domain and domain upon authentication from my subdomain.

For Login

 public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);

                    Account account = new Account();
                    //modify the Domain attribute of the cookie to the second level domain
                    HttpCookie MyCookie = FormsAuthentication.GetAuthCookie(model.UserName, model.RememberMe);
                    MyCookie.Domain = "domain.com";//the second level domain name
                    Response.AppendCookie(MyCookie);

                    string userName = account.GetUserName(model.UserName);
                    Session["ActualName"] = userName;
                    HttpCookie userCookie = new HttpCookie("IGNUS");
                    userCookie.Domain = "domain.com";
                    userCookie.Values["Name"] = userName;
                    if (model.RememberMe)
                        userCookie.Expires = DateTime.Now.AddDays(2);
                    Response.Cookies.Add(userCookie);

                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Member");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }
For LogOut

 public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();

            HttpCookie userCookie = new HttpCookie("IGNUS");
            userCookie.Domain = "domain.com";
            userCookie.Expires = DateTime.Now.AddDays(-1);

            HttpCookie staticAuthCookie = new HttpCookie(".ASPXAUTH");
            staticAuthCookie.Domain = "domain.com";
            staticAuthCookie.Expires = DateTime.Now.AddDays(-1);

            Response.Cookies.Add(userCookie);
            Response.Cookies.Add(staticAuthCookie);

            return RedirectToAction("LogOn");
        }

1 comment:

  1. if you are using the membership provider of asp.net then your solution is in the web.config check this detailed post about single sign on for asp.net http://logicum.co/asp-net-subdomains-single-sign-on/

    ReplyDelete