using System; using System.Collections.Generic; using System.Text; using System.Web; using System.Security.Principal; using System.Web.Security; using System.Data.OleDb; using System.Xml; using System.Web.Configuration; using Sage.Platform.Application; using Sage.SalesLogix; using System.Web.Caching; using log4net; using SSSWorld.Common; using System.Data; using Sage.Platform.Data; namespace SSSWorld.Slx72.Web.Utility { /// /// Replacement for the Saleslogix MixedModeSecurityModule. /// It uses the connection string from the legacy site for the authentication. /// This avoids having to set up the delegation (which implies running the service as a trusted user). /// To use it, replace the configured MixedModeSecurityModule in web.config. /// The "legacy" connection string must be set up properly in the registry (using the legacy web manager). /// public class MixedModeSecurityModuleHelper : IHttpModule { private static readonly ILog LOG = LogManager.GetLogger(typeof(MixedModeSecurityModuleHelper)); public void Init(HttpApplication context) { context.EndRequest += new EventHandler(this.context_EndRequest); context.PostAcquireRequestState += new EventHandler(this.context_PostAcquireRequestState); (context.Modules["FormsAuthentication"] as FormsAuthenticationModule).Authenticate += new FormsAuthenticationEventHandler(this.MixedModeSecurityModule_Authenticate); } private void context_EndRequest(object sender, EventArgs e) { HttpContext context = ((HttpApplication)sender).Context; if (context.Items["_hid401Status"] != null) { context.Response.StatusCode = 0x191; context.Items["_hid401Status"] = null; LOG.Debug("Restored 401 status"); } } /// /// Retrieve the info that has been stored in the cache during the Authenticate /// event, and if available initializes the user's context with it. /// /// /// private void context_PostAcquireRequestState(object sender, EventArgs e) { HttpContext context = ((HttpApplication)sender).Context; string str = context.Request.ServerVariables["LOGON_USER"]; object obj2 = context.Cache.Get(str + "WinAuth"); if (obj2 != null) { AuthUserInfo info = (AuthUserInfo)obj2; if (!string.IsNullOrEmpty(info._UserCode) && (ApplicationContext.Current != null)) { if (!ApplicationContext.Current.Services.Get().IsAuthenticated) { Membership.ValidateUser(info._UserCode, SLXEncryption.Decrypt(info._Password, info._UserId).Trim()); } if (ApplicationContext.Current != null) { IContextService service = ApplicationContext.Current.Services.Get(true); if (((service != null) && (service["TimeZone"] == null)) && (string.IsNullOrEmpty(context.Request.Params["loadtz"]) && !string.IsNullOrEmpty(info._UserCode))) { string absolutePath = context.Request.Url.AbsolutePath; context.Response.Redirect(string.Format("~/WinAuthLoad.aspx?next_url={0}&loadtz=true", absolutePath)); } context.Cache.Remove(str + "WinAuth"); } } } } private IPrincipal CreateUser(string user, WindowsIdentity wi, HttpContext context) { string str = WebConfigurationManager.AppSettings["UseWindowsPrincipal"]; if (!string.IsNullOrEmpty(str) && (str != "false")) { return new WindowsPrincipal(wi); } AuthenticationSection section = (AuthenticationSection)WebConfigurationManager.GetSection("system.web/authentication"); int totalMinutes = (int)section.Forms.Timeout.TotalMinutes; FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user, DateTime.Now, DateTime.Now.AddMinutes((double)totalMinutes), false, "", FormsAuthentication.FormsCookiePath); SetAuthenticationCookie(context, ticket); return new GenericPrincipal(new FormsIdentity(ticket), null); } private static void GetUserNamePass(WindowsIdentity identity, AuthUserInfo aui) { // don't use this - trying to access dataservice will cause NullRef //IDataService dataService = ApplicationContext.Current.Services.Get(); string connectionString = GetConnectionString(); String sid = identity.User.ToString(); //LOG.Debug("Retrieving user info for " + identity.Name + " (SID: " + sid + ")"); try { //LOG.Debug("Using connection string " + connectionString); using (DBConnectionWrapper con = new DBConnectionWrapper(connectionString)) { //LOG.Debug("Connected"); if (String.Equals(con.GetField("USEWINDOWSAUTH", "SYSTEMINFO", "SYSTEMINFOID='PRIMARY'"), "T")) { using (IDataReader reader = con.OpenDataReader("SELECT USERCODE,USERPW, US.USERID, UI.USEWINDOWSAUTH FROM USERSECURITY US JOIN USERINFO UI ON US.USERID=UI.USERID WHERE UI.WINDOWSSID = ?", sid)) { //LOG.Debug("Got user info"); if (reader.Read()) { aui._UserCode = reader.GetString(0); aui._Password = reader.GetString(1); aui._UserId = reader.GetString(2); } else { LOG.Info("Could not locate usersecurity record for sid " + sid); } } } LOG.Debug("Windows Authentication: Returning [" + aui._UserCode + "],[" + aui._UserId + "]"); } } catch (OleDbException x) { LOG.Debug("Unable to create connection for Windows authentication - Make sure connection is setup in legacy web settings", x); return; } catch (Exception x) { LOG.Warn("Uncaught exception in GetUserPass", x); throw; } } /// /// Retrieve connection string from the registry /// (this relies on the legacy web settings being configured correctly) /// /// private static String GetConnectionString() { return SSSWorld.Common.Saleslogix.SLXConnectionInfo.GetWebConnection( HttpContext.Current.Server.MachineName, HttpContext.Current.Request.Url.Port).BuildConnectionString(); /* XmlReader reader = XmlReader.Create(HttpContext.Current.Server.MapPath("~/connection.config")); if (!reader.ReadToDescendant("ConString")) throw new InvalidOperationException("Can't locate ConString node"); reader.Read(); OleDbConnectionStringBuilder bldr = new OleDbConnectionStringBuilder(reader.Value); bldr["User Id"] = "ADMIN"; bldr["Password"] = "sssworld231"; return bldr.ConnectionString; */ } private void MixedModeSecurityModule_Authenticate(object sender, FormsAuthenticationEventArgs e) { HttpContext context = e.Context; if (context.Request.Cookies[FormsAuthentication.FormsCookieName] != null) { FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(context.Request.Cookies[FormsAuthentication.FormsCookieName].Value); e.User = new GenericPrincipal(new FormsIdentity(ticket), new string[0]); string str = context.Request.ServerVariables["LOGON_USER"]; if (!string.IsNullOrEmpty(str)) { context.Response.Cookies.Remove("." + str); } } else if (context.Request.RawUrl.ToUpper().Contains("WINDOWS.ASPX")) { string str2 = context.Request.ServerVariables["LOGON_USER"]; if (string.IsNullOrEmpty(str2)) { WindowsIdentity anonymous = WindowsIdentity.GetAnonymous(); e.User = new WindowsPrincipal(anonymous); } else if ((context.Request.Cookies["." + str2] == null) && ((!string.IsNullOrEmpty(str2) && (context.Request.LogonUserIdentity.GetType() == typeof(WindowsIdentity))) && context.Request.LogonUserIdentity.IsAuthenticated)) { AuthUserInfo aui = new AuthUserInfo(); lock (aui) { GetUserNamePass(context.Request.LogonUserIdentity, aui); if (context.Cache[str2 + "WinAuth"] != null) { context.Cache[str2 + "WinAuth"] = aui; } if (!string.IsNullOrEmpty(aui._UserCode)) { context.Cache.Add(str2 + "WinAuth", aui, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(5.0), CacheItemPriority.NotRemovable, null); e.User = this.CreateUser(aui._UserCode, context.Request.LogonUserIdentity, context); } else { HttpCookie cookie = new HttpCookie("." + str2); cookie.Expires = DateTime.Now.AddSeconds(30.0); cookie.HttpOnly = true; context.Response.SetCookie(cookie); } } } } } private static void SetAuthenticationCookie(HttpContext context, FormsAuthenticationTicket ticket) { string str = FormsAuthentication.Encrypt(ticket); HttpCookie cookie = new HttpCookie(".SLXAUTH"); cookie.Value = str; cookie.Secure = FormsAuthentication.RequireSSL; cookie.Domain = FormsAuthentication.CookieDomain; cookie.HttpOnly = false; context.Response.Cookies.Add(cookie); } private class AuthUserInfo { // Fields public string _Password; public string _UserCode; public string _UserId; // Methods public AuthUserInfo() { this._UserCode = ""; this._Password = ""; this._UserId = ""; } public AuthUserInfo(string uc, string pw, string id) { this._UserCode = uc; this._Password = pw; this._UserId = id; } } public void Dispose() { } } }