I have two sites that I'm trying to implement single sign on for by setting up shared session state. I have followed the steps here:
Configured the SQL server to support session state
Set the session state property in both web configs, same in each application:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" sqlConnectionString="Data Source=sqlserver;user id=user;password=password;Application Name=MySession" cookieless="false" />
Added a machine key property:
<machineKey validationKey="xxxx" decryptionKey="yyyy" validation="SHA1" decryption="AES" />
Implemented the HttpModule to modify the domain session cookie to use the top level domain:
using System; using System.Web; using System.Reflection; using System.Configuration; namespace CSASPNETShareSessionBetweenSubDomainsModule { /// <summary> /// A HttpModule used for sharing the session between Applications in /// sub domains. /// </summary> public class SharedSessionModule : IHttpModule { // Cache settings on memory. protected static string applicationName = ConfigurationManager.AppSettings["ApplicationName"]; protected static string rootDomain = ConfigurationManager.AppSettings["RootDomain"]; #region IHttpModule Members /// <summary> /// Initializes a module and prepares it to handle requests. /// </summary> /// <param name="context"> /// An System.Web.HttpApplication /// that provides access to the methods, /// properties, and events common to all application objects within /// an ASP.NET application. /// </param> public void Init(HttpApplication context) { // This module requires both Application Name and Root Domain to work. if (string.IsNullOrEmpty(applicationName) || string.IsNullOrEmpty(rootDomain)) { return; } // Change the Application Name in runtime. FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic); HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null); FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic); appNameInfo.SetValue(theRuntime, applicationName); // Subscribe Events. context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute); } /// <summary> /// Disposes of the resources (other than memory) used by the module /// that implements. /// </summary> public void Dispose() { } #endregion /// <summary> /// Before sending response content to client, change the Cookie to Root Domain /// and store current Session Id. /// </summary> /// <param name="sender"> /// An instance of System.Web.HttpApplication that provides access to /// the methods, properties, and events common to all application /// objects within an ASP.NET application. /// </param> void context_PostRequestHandlerExecute(object sender, EventArgs e) { try { HttpApplication context = (HttpApplication) sender; // ASP.NET store a Session Id in cookie to specify current Session. HttpCookie cookie = context.Response.Cookies["ASP.NET_SessionId"]; if (context.Session != null && !string.IsNullOrEmpty(context.Session.SessionID)) { // Need to store current Session Id during every request. cookie.Value = context.Session.SessionID; // All Applications use one root domain to store this Cookie // So that it can be shared. if (rootDomain != "localhost") { cookie.Domain = rootDomain; } // All Virtual Applications and Folders share this Cookie too. cookie.Path = "/"; } } catch (Exception ex) { return; } } } }
... and added it to the web config:
<modules runAllManagedModulesForAllRequests="true">
<add name="SharedSessionModule" type="CSASPNETShareSessionBetweenSubDomainsModule.SharedSessionModule, CSASPNETShareSessionBetweenSubDomainsModule, Version=1.0.0.0, Culture=neutral"/>
</modules>
Additionally, in site B, my UserService is pointing to site B, so they are sharing the same pool of users.
When I log into site A, I see these cookies: a session cookie where the domain is the top level domain, as well as another session cookie with the full domain and an empty value.
When I go to site B, I am not logged in, but I do see the matching session cookie from site A, as well as a second empty session cookie with the domain of site B:
I am able to log into site B, and I am now logged in on both sites. When I try to log out of site A, nothing happens; when I log out of site B, I get logged out of site B AND site A.
What is wrong with my session state? Is it because of that extra empty ASP.NET_SessionId cookie, and if so, how do I get rid of that? Is there a way I can check the session state in my code and log the user in if that session cookie exists, or force the session to use correct ASP.NET_SessionId cookie?
EDIT: I added the code to remove the duplicate cookies, but when I debug, my code is only seeing one cookie:
but when I check the cookies in Chrome inspector, there are two.
EDIT 2: So I resolved the duplicate cookie issue now, but SSO still isn't working. I opened up site A, logged in, opened up site B. Checked the cookies on both, and they both have one single ASP.NET_SessionId cookie with the same Value and Domain, but I'm still not logged into site B