using System; using System.Linq; using System.Net; using System.Reflection; using System.Security; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.Xml; using BeWo.Data; using BeWo.Data.Access; using BeWo.Data.Entities; using BeWo.Service.Core; using BeWo.Service.ServiceUtils; using BS.Shared.Attributes; using BS.Shared.Extensions; using NHibernate.Hql.Ast.ANTLR.Tree; namespace BeWo.Service.Security { public class SecurityContextInitializer : ICallContextInitializer { private readonly string[] ALLOW_ALWAYS = new string[] { //"Download", //"Download2", //"DownloadInfo", //"GetUpdatePlan", //"GetUpdateFile", "ResetAllTenants", "IsUserValid", "IsUserValidTwoFactor", "ResetTenant", "GetEmailForUserName", "GetTranslationDictionary", }; private readonly string[] ALLOW_ONLY_WITH_LOGIN = new string[] { "LoadUserByNameAndPassword", "LoadUserByLoginName", "GetMandator", "LoadEmployee", "GetPersonsHavingBirthday", "GetLastLogins", "GetSupportConceptsWithConferenceDate", "GetExpiringSupportConcepts", "GetPublishedNewsItemsForEmployee", "GetAllActiveEmployeesCompact", "GetHomeViewPanels", "LoadCompactEmployee", "GetTranslationDictionary", "ConvertToNewSubstitutionType" }; public void AfterInvoke(object pCorrelationState) { if (pCorrelationState is LoggedInUserOperationContextExt) { OperationContext.Current.Extensions.Remove((LoggedInUserOperationContextExt)pCorrelationState); } } public object BeforeInvoke(InstanceContext pInstanceContext, IClientChannel pChannel, Message pMessage) { try { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; var lTemp = pMessage.Headers.Action.Split("/"); string lMethodName = lTemp[lTemp.Count - 1]; string lServiceInterface = lTemp[lTemp.Count - 2]; // TODO Hier kann man jetzt etwas bauen wer sich für welchen service autorisieren muss... if (ALLOW_ALWAYS.Contains(lMethodName)) { return null; } else { // Vergessen neue Methode einzutragen? } string lUserName = null, lPassword = null; int lSecurityHeaderIndex = pMessage.Headers.FindHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); if (lSecurityHeaderIndex > -1) { XmlReader lReader = pMessage.Headers.GetReaderAtHeader(lSecurityHeaderIndex); if (lReader.ReadToFollowing("Username")) { lUserName = lReader.ReadString(); } if (lReader.ReadToFollowing("Password")) { lPassword = lReader.ReadString(); } ApplicationUser lUser = DAOFactory.UserDAO.FindUserByLoginName(lUserName); if (lUser != null && DAOFactory.UserDAO.CheckPassword(lUser, lPassword)) { if (!HasMethodAuthorization(lUser, lMethodName, pMessage)) { throw new SecurityException("Methode nicht autorisiert: " + lMethodName); } var lExt = new LoggedInUserOperationContextExt { User = lUser, LoginName = lUserName, UnhashedPassword = lPassword }; OperationContext.Current.Extensions.Add(lExt); return lExt; } } throw new SecurityException("Nicht autorisiert"); } catch (Exception e) { throw Utils.CreateBeWoFaultException(e); } } private bool HasMethodAuthorization(ApplicationUser pUser, string methodName, Message pMessage) { if (ALLOW_ONLY_WITH_LOGIN.Contains(methodName)) { return true; } else { // Vergessen neue Methode einzutragen? } var rights = Utils.GetGrantedRights(pUser); // Finde Action var lTemp = pMessage.Headers.Action?.Split("/"); if (lTemp is null) lTemp = pMessage.Headers.To.Segments.ToList(); if (lTemp is null) throw new ArgumentException("Kann Action nicht finden"); // Extrahiere MethodeName + ServiceInterface string lMethodName = lTemp[lTemp.Count - 1].Trim('/'); string lServiceInterface = lTemp[lTemp.Count - 2].Trim('/'); try { var attribute = ServiceHelper.GetCustomAttribute(lServiceInterface, lMethodName); if (attribute != null) { return attribute.HasPermission(rights); } } catch (Exception e) { } return true; } } }