using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; using Microsoft.Net.Http.Headers; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Sacs.Web.Components; using Sarand.BusinessMgr.Net.Core.Web.App; using Sarand.BusinessMgr.Net.Core.Web.Models; using Sarand.BusinessMgr.Net.Standard.Base.App; using Sarand.BusinessMgr.Net.Standard.Base.Bus; using Sarand.BusinessMgr.Net.Standard.Base.Consoles; using Sarand.BusinessMgr.Net.Standard.Base.Core; using Sarand.BusinessMgr.Net.Standard.Base.Mgr; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.CodeTypes; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Diary; using Sarand.Net.Standard.Base.Email; using Sarand.Net.Standard.Base.Helpers; using Sarand.Net.Standard.Base.Interfaces; using Sarand.Net.Standard.Base.ItemData; using Sarand.Net.Standard.Base.ItemDocs; using Sarand.Net.Standard.Base.ItemOptions; using Sarand.Net.Standard.Base.ReferenceData; using Sarand.Net.Standard.Base.Security; using Sarand.Net.Standard.Base.UpdateLog; using Sarand.Net.Standard.Base.Utils; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Web; namespace Sarand.BusinessMgr.Net.Core.Web.Controllers { //======================================================================= public abstract class SbmController_Web : SbmController_Base { //------------------------------------------------------------------- // Data members. //------------------------------------------------------------------- // Protected construction. protected SbmController_Web(SbmLocaliser localiser) : base(localiser) { // Initialise console (debug) logging listener. //if (Directory.Exists(App.LoggingRootFolder) && SbmSystem.DebugMode) // SbmConsoleListener.ConfigureDebugListener(App.LoggingRootFolder); if (DebugMode) SaLogger.Trace($"{GetType().Name}.CTR"); } protected override void Dispose(bool disposing) { if (disposing) { } base.Dispose(disposing); } //------------------------------------------------------------------- // Properties. public override SbmSessionContext SessionContext { get { return SessionData?.SessionContext ?? null; } } //------------------------------------------------------------------- // Action execution events. //------------------------------------------------------------------- public override void OnActionExecuting(ActionExecutingContext filterContext) { //if (DebugMode) SaLogger.Debug($"{SysUtil.Fn}" + (ViewData.Model != null ? " Model: " + ViewData.Model : "")); // Refreh model properties. SbmModel_Base baseModel = ViewData.Model as SbmModel_Base; RefreshModel(baseModel); base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { //if (DebugMode) SaLogger.Debug($"{SysUtil.Fn}" + (ViewData.Model != null ? " Model: " + ViewData.Model : "")); // Refreh model properties. SbmModel_Base baseModel = ViewData.Model as SbmModel_Base; RefreshModel(baseModel); // Store session data if present - as potentially modfied. if (SessionData != null) { // Most actions will store the session data in case it's been modified. // Some actions (eg. score password) don't need to. if (StoreSessionData) { String sessionDataJson = JsonConvert.SerializeObject(SessionData); HttpContext.Session.Set(SessionStorage.SessionKey_SessionData, SessionStorage.sessionDataEncoding.GetBytes(sessionDataJson)); } } else HttpContext.Session.Remove(SessionStorage.SessionKey_SessionData); // Response headers. if (baseModel != null && baseModel.ProhibitCache) { if (Response.Headers.ContainsKey(HeaderNames.CacheControl)) Response.Headers.Remove(HeaderNames.CacheControl); Response.Headers.Add(HeaderNames.CacheControl, "no-cache, no-store, must-revalidate"); Response.Headers.Add(HeaderNames.Pragma, "no-cache"); Response.Headers.Add(HeaderNames.Expires, "0"); } base.OnActionExecuted(filterContext); } //------------------------------------------------------------------- // Model. //------------------------------------------------------------------- protected void RefreshModel(SbmModel_Base model) { if (model == null) return; // Session data. model.Controller = this; model.SessionData_Web = SessionData; // Redirect locations. model.RedirectLocation.Base = GetRedirectLocation(RedirectLocation.WebAppBase); model.RedirectLocation.Home = GetRedirectLocation(RedirectLocation.WebAppHome); model.RedirectLocation.Home_SessionExpired = GetRedirectLocation(RedirectLocation.WebAppHome_SessionExpired); } //------------------------------------------------------------------- // Online encryption parameters. //------------------------------------------------------------------- // Portal Request Password encryption parameters (key & IV) are defined in // the base Controller so that they can be shared with the Admin application. // NB IV value is generated from the key and fixed so that it doesn't change when the application restarts. // IV Must be regenerated if key is changed. protected static String Base64Key_RequestPassword_Portal { get; } = SacsEncryptionHelper.EncodePlainKey("[5Abus1neSSmGR~Request#Password}", SacsEncryptionHelper.KeyLength); //private static String Base64IV_RequestPassword_Generated_Portal = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword_Portal); protected static String Base64IV_RequestPassword_Portal { get; } = "8TRhBayBJZmACQ6pld1F9A=="; //------------------------------------------------------------------- // Session. //------------------------------------------------------------------- public bool ValidUserSession { get { return SessionData?.ValidUser ?? false; } } public DbUpdateInfo DbUpdateInfo { get { return SessionData?.DbUpdateInfo ?? new DbUpdateInfo(null, "", SbmSystem.ComputerName); } } // Referrer. public String Referer { get { return Request.Headers["Referer"].ToString(); } } public bool ValidReferer { get { return !StringUtil.IsEmpty(Referer); } } /// Store session data, eg. to start a new user session on sign-in. protected bool SetSessionData(SbmSessionData_Web sessionData) { if (sessionStorage.SessionData != null) return false; sessionStorage.SessionData = sessionData; return true; } protected void ClearSessionData() { if (HttpContext.Session.IsAvailable) HttpContext.Session.Clear(); sessionStorage.SessionData = null; } //------------------------------------------------------------------- // Session storage. public class SessionStorage { public SbmSessionData_Web SessionData { get; set; } public static String SessionKey_SessionData { get; } = "SbmSessionData"; public static Encoding sessionDataEncoding { get; } = Encoding.UTF8; //JSON Serialisation. public class SbmSessionDataContractResolver : DefaultContractResolver { // To allow private properties to be deserialised. // NB Only applies to top level properties in the serialised object. protected override List GetSerializableMembers(Type objectType) { var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; MemberInfo[] fields = objectType.GetFields(flags); return fields .Concat(objectType.GetProperties(flags).Where(propInfo => propInfo.CanWrite)) .ToList(); } protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { return base.CreateProperties(type, MemberSerialization.Fields); } }; public static JsonSerializerSettings JsonDeserialisationSettings = new JsonSerializerSettings { ContractResolver = new SbmSessionDataContractResolver(), // Force all deserialised objects to be replaced - to avoid proxy lists not populating. ObjectCreationHandling = ObjectCreationHandling.Replace }; } private readonly SessionStorage sessionStorage = new SessionStorage(); public static JsonSerializerSettings SbmSessionDataJsonSerializerSettings { get { return SessionStorage.JsonDeserialisationSettings; } } //------------------------------------------------------------------- public SbmSessionData_Web SessionData { get { try { // Retrieve session data if not already in controller. if (sessionStorage.SessionData == null) { byte[] sessionDataBytes = null; HttpContext.Session.TryGetValue(SessionStorage.SessionKey_SessionData, out sessionDataBytes); if (sessionDataBytes != null) { String sessionDataJson = SessionStorage.sessionDataEncoding.GetString(sessionDataBytes); sessionStorage.SessionData = DeserializeSessionData(sessionDataJson); } } return sessionStorage.SessionData; } catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {exc.GetType().Name} - {exc.Message}{exc.GetStackEntries().Concat("", "\n\t")}"); } return null; } } protected abstract SbmSessionData_Web DeserializeSessionData(String sessionDataJson); //------------------------------------------------------------------- } //======================================================================= }