I have a Single Sign-on solution which is working great in our test environment. It uses Cross-Sub-Domain cookies to share the authentication ticket between 2 web applications. Sign-on is done only on one of the applications and on the second site the user is authenticated by the cookie created by the first site.
The problem is that when I roll it into the production environment the single sign-on no longer works. I'm looking for any ideas on why this might be. More details below:
1) Both apps are implemented using ASP.NET MVC2
2) In our test environment both websites are sitting on a single server, with different websites in IIS and host headers used to serve the 2 web applications. In production the sites are on different servers which are geographically separated. They use the same sub-domains though.
3) Both sites have SSL setup and accessed via https; this is done in both test and production using the same self-signed wild-card certificate.
4) Users login to site1 and then the application automatically retrieves data from site2 using AJAX and JSONP.
5) if the sites are site1.example.com and site2.example.com, the following are the important parts of the web.config shared between site1 and site2:
...
<authentication mode="Forms">
<forms name=".myapp" domain=".example.com" slidingExpiration="true" loginUrl="~/Account/LogOn" timeout="30"/>
</authentication>
...
<machineKey validationKey="KEY1..." decryptionKey="KEY2..."
validation="SHA1" decryption="AES" />
...
NOTE: One thing I do wonder about the stuff above is, does the authentication ticket get encrypted\hashed in such a way that it can only be decrypted on the same server? That would explain my issue; but if this is the case how can I ensure that the server for both site1 and site2 can decrypt my authentication cookie? KEY1 and KEY2 are both definitely the same on both sites\servers.
6) On Site1 the Roles the user is in are also inserted into the cookie using the following:
public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
ViewData["rememberMe"] = rememberMe;
return View(new SiteViewModel(this));
}
FormsAuth.SignIn(userName, rememberMe);
// Add roles to cookie
string[] roles = Roles.GetRolesForUser(userName);
HttpCookie cookie = FormsAuthentication.GetAuthCookie(User.Identity.Name, rememberMe);
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
// Store roles inside the Forms cookie.
FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(ticket.Version, userName,
ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, String.Join("|", roles), ticket.CookiePath);
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.HttpOnly = false;
Response.Cookies.Remove(cookie.Name);
Response.AppendCookie(cookie);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
7) The roles are restored on Site2 using the following:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (Context.Request.IsAuthenticated)
{
FormsIdentity ident = (FormsIdentity)Context.User.Identity;
string[] arrRoles = ident.Ticket.UserData.Split(new[] { '|' });
Context.User = new System.Security.Principal.GenericPrincipal(ident, arrRoles);
}
}
EDIT:
8) This is a printout of the assemblies referenced by the applications on both servers:
mscorlib: 2.0.0.0
System: 2.0.0.0
System.Configuration: 2.0.0.0
System.Xml: 2.0.0.0
System.ComponentModel.DataAnnotations: 3.5.0.0
System.Core: 3.5.0.0
System.Data: 2.0.0.0
System.EnterpriseServices: 2.0.0.0
System.Transactions: 2.0.0.0
System.Data.Entity: 3.5.0.0
System.Runtime.Serialization: 3.0.0.0
SMDiagnostics: 3.0.0.0
System.Web: 2.0.0.0
System.Drawing: 2.0.0.0
System.Web.RegularExpressions: 2.0.0.0
System.Web.Services: 2.0.0.0
System.Web.Abstractions: 3.5.0.0
System.Web.Extensions: 3.5.0.0
System.Data.Linq: 3.5.0.0
System.Xml.Linq: 3.5.0.0
System.ServiceModel: 3.0.0.0
System.IdentityModel: 3.0.0.0
System.ServiceModel.Web: 3.5.0.0
System.Web.Mvc: 1.0.0.0
System.Web.Routing: 3.5.0.0
xVal: 1.0.0.0