From a6bff2d8b08721bf3413d122c808c6df2dac0cd6 Mon Sep 17 00:00:00 2001 From: Rene Evertz Date: Thu, 20 Feb 2025 18:39:11 +0100 Subject: [PATCH] AdminService Init (Prototyp) --- Host/AdminService.svc | 1 + Host/Host.csproj | 1 + Host/Web.config | 63 ++++++++++++++----- Service/Service.csproj | 12 ++++ .../ServiceBehavior/AdminHibernateBehavior.cs | 35 +++++++++++ .../AdminHibernateBehaviorExtension.cs | 20 ++++++ .../AdminHibernateContextInitializer.cs | 25 ++++++++ .../AdminMultitenancyBehavior.cs | 36 +++++++++++ .../AdminMultitenancyBehaviorExtension.cs | 19 ++++++ .../AdminMultitenancyContextInitializer.cs | 55 ++++++++++++++++ .../ServiceBehavior/AdminSecurityBehavior.cs | 39 ++++++++++++ .../AdminSecurityBehaviorExtension.cs | 15 +++++ .../AdminServiceMessageInspector.cs | 40 ++++++++++++ Service/ServiceContracts/IAdminService.cs | 18 ++++++ .../ServiceImplementations/AdminServiceImp.cs | 19 ++++++ 15 files changed, 381 insertions(+), 17 deletions(-) create mode 100644 Host/AdminService.svc create mode 100644 Service/ServiceBehavior/AdminHibernateBehavior.cs create mode 100644 Service/ServiceBehavior/AdminHibernateBehaviorExtension.cs create mode 100644 Service/ServiceBehavior/AdminHibernateContextInitializer.cs create mode 100644 Service/ServiceBehavior/AdminMultitenancyBehavior.cs create mode 100644 Service/ServiceBehavior/AdminMultitenancyBehaviorExtension.cs create mode 100644 Service/ServiceBehavior/AdminMultitenancyContextInitializer.cs create mode 100644 Service/ServiceBehavior/AdminSecurityBehavior.cs create mode 100644 Service/ServiceBehavior/AdminSecurityBehaviorExtension.cs create mode 100644 Service/ServiceBehavior/AdminServiceMessageInspector.cs create mode 100644 Service/ServiceContracts/IAdminService.cs create mode 100644 Service/ServiceImplementations/AdminServiceImp.cs diff --git a/Host/AdminService.svc b/Host/AdminService.svc new file mode 100644 index 000000000..0700e1ca4 --- /dev/null +++ b/Host/AdminService.svc @@ -0,0 +1 @@ +<%@ ServiceHost Language="C#" Debug="true" Service="BeWo.Service.ServiceImplementations.AdminServiceImp" %> diff --git a/Host/Host.csproj b/Host/Host.csproj index 2256ad3ef..f4e0e7fa0 100644 --- a/Host/Host.csproj +++ b/Host/Host.csproj @@ -168,6 +168,7 @@ + diff --git a/Host/Web.config b/Host/Web.config index 2a6bfdf6f..a45800f20 100644 --- a/Host/Web.config +++ b/Host/Web.config @@ -113,25 +113,16 @@ + + + + + + + - - - - - - - - - - - - - - - - - + @@ -184,7 +175,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -197,6 +215,13 @@ + + + + + + + @@ -212,11 +237,15 @@ + + + + diff --git a/Service/Service.csproj b/Service/Service.csproj index 1beac58b7..f96bb9fc7 100644 --- a/Service/Service.csproj +++ b/Service/Service.csproj @@ -191,6 +191,7 @@ 3.0 + ..\packages\System.Text.Encoding.CodePages.5.0.0\lib\net461\System.Text.Encoding.CodePages.dll @@ -478,8 +479,18 @@ + + + + + + + + + + @@ -492,6 +503,7 @@ + diff --git a/Service/ServiceBehavior/AdminHibernateBehavior.cs b/Service/ServiceBehavior/AdminHibernateBehavior.cs new file mode 100644 index 000000000..42608c307 --- /dev/null +++ b/Service/ServiceBehavior/AdminHibernateBehavior.cs @@ -0,0 +1,35 @@ +using BeWo.Service.UnitOfWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel.Channels; +using System.ServiceModel.Description; +using System.ServiceModel.Dispatcher; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminHibernateBehavior : IEndpointBehavior + { + public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) + { + } + + public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) + { + } + + public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) + { + foreach (DispatchOperation iOperation in endpointDispatcher.DispatchRuntime.Operations) + { + iOperation.CallContextInitializers.Add(new AdminHibernateContextInitializer()); + } + } + + public void Validate(ServiceEndpoint endpoint) + { + } + } +} diff --git a/Service/ServiceBehavior/AdminHibernateBehaviorExtension.cs b/Service/ServiceBehavior/AdminHibernateBehaviorExtension.cs new file mode 100644 index 000000000..cfb6fc892 --- /dev/null +++ b/Service/ServiceBehavior/AdminHibernateBehaviorExtension.cs @@ -0,0 +1,20 @@ +using BeWo.Service.UnitOfWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel.Configuration; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminHibernateBehaviorExtension : BehaviorExtensionElement + { + public override Type BehaviorType => typeof(AdminHibernateBehavior); + + protected override object CreateBehavior() + { + return new AdminHibernateBehavior(); + } + } +} diff --git a/Service/ServiceBehavior/AdminHibernateContextInitializer.cs b/Service/ServiceBehavior/AdminHibernateContextInitializer.cs new file mode 100644 index 000000000..8517ad83f --- /dev/null +++ b/Service/ServiceBehavior/AdminHibernateContextInitializer.cs @@ -0,0 +1,25 @@ +using BeWo.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel; +using System.ServiceModel.Channels; +using System.ServiceModel.Dispatcher; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminHibernateContextInitializer : ICallContextInitializer + { + public void AfterInvoke(object pCorrelationState) + { + + } + + public object BeforeInvoke(InstanceContext pInstanceContext, IClientChannel pChannel, Message pMessage) + { + return null; + } + } +} diff --git a/Service/ServiceBehavior/AdminMultitenancyBehavior.cs b/Service/ServiceBehavior/AdminMultitenancyBehavior.cs new file mode 100644 index 000000000..bd037b4f5 --- /dev/null +++ b/Service/ServiceBehavior/AdminMultitenancyBehavior.cs @@ -0,0 +1,36 @@ +using BeWo.Service.Multitenancy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel.Channels; +using System.ServiceModel.Description; +using System.ServiceModel.Dispatcher; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminMultitenancyBehavior : IEndpointBehavior + { + public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) + { + } + + public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) + { + throw new NotImplementedException("This is a server behavior only"); + } + + public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) + { + foreach (DispatchOperation iOperation in endpointDispatcher.DispatchRuntime.Operations) + { + iOperation.CallContextInitializers.Add(new AdminMultitenancyContextInitializer()); + } + } + + public void Validate(ServiceEndpoint endpoint) + { + } + } +} diff --git a/Service/ServiceBehavior/AdminMultitenancyBehaviorExtension.cs b/Service/ServiceBehavior/AdminMultitenancyBehaviorExtension.cs new file mode 100644 index 000000000..ac345391d --- /dev/null +++ b/Service/ServiceBehavior/AdminMultitenancyBehaviorExtension.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel.Configuration; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminMultitenancyBehaviorExtension : BehaviorExtensionElement + { + public override Type BehaviorType => typeof(AdminMultitenancyBehavior); + + protected override object CreateBehavior() + { + return new AdminMultitenancyBehavior(); + } + } +} diff --git a/Service/ServiceBehavior/AdminMultitenancyContextInitializer.cs b/Service/ServiceBehavior/AdminMultitenancyContextInitializer.cs new file mode 100644 index 000000000..6974f261e --- /dev/null +++ b/Service/ServiceBehavior/AdminMultitenancyContextInitializer.cs @@ -0,0 +1,55 @@ +using BeWo.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel.Channels; +using System.ServiceModel; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Xml; +using System.ServiceModel.Dispatcher; +using BeWo.Service.Core; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminMultitenancyContextInitializer : ICallContextInitializer + { + public void AfterInvoke(object pCorrelationState) + { + if (pCorrelationState is MultitenancyOperationContextExt) + { + OperationContext.Current.Extensions.Remove((MultitenancyOperationContextExt)pCorrelationState); + } + } + + public object BeforeInvoke(InstanceContext pInstanceContext, IClientChannel pChannel, Message pMessage) + { + string lTenant = null; + + try + { + if (pMessage.Properties?.Via is Uri uri) + { + var query = HttpUtility.ParseQueryString(uri.Query); + var tenant = query["tenant"]; + + lTenant = tenant; + } + + if (!string.IsNullOrEmpty(lTenant)) + { + var lExt = new MultitenancyOperationContextExt { Tenant = lTenant }; + OperationContext.Current.Extensions.Add(lExt); + return lExt; + } + + return null; + } + catch (Exception e) + { + throw Utils.CreateBeWoFaultException(e); + } + } + } +} diff --git a/Service/ServiceBehavior/AdminSecurityBehavior.cs b/Service/ServiceBehavior/AdminSecurityBehavior.cs new file mode 100644 index 000000000..0e569871f --- /dev/null +++ b/Service/ServiceBehavior/AdminSecurityBehavior.cs @@ -0,0 +1,39 @@ +using BeWo.Data; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Configuration; +using System.Linq; +using System.ServiceModel; +using System.ServiceModel.Channels; +using System.ServiceModel.Description; +using System.ServiceModel.Dispatcher; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminSecurityBehavior : IEndpointBehavior + { + public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) + { + // Keine zusätzlichen Bindungsparameter erforderlich + } + + public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) + { + // Verhalten für Clients - hier nicht benötigt + } + + public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) + { + // Füge einen Message Inspector hinzu, um eingehende Requests zu überprüfen + endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new AdminServiceMessageInspector()); + } + + public void Validate(ServiceEndpoint endpoint) + { + // Optional: Endpunktvalidierung (falls erforderlich) + } + } +} diff --git a/Service/ServiceBehavior/AdminSecurityBehaviorExtension.cs b/Service/ServiceBehavior/AdminSecurityBehaviorExtension.cs new file mode 100644 index 000000000..1f3cfb260 --- /dev/null +++ b/Service/ServiceBehavior/AdminSecurityBehaviorExtension.cs @@ -0,0 +1,15 @@ +using System; +using System.ServiceModel.Configuration; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminSecurityBehaviorExtension : BehaviorExtensionElement + { + public override Type BehaviorType => typeof(AdminSecurityBehavior); + + protected override object CreateBehavior() + { + return new AdminSecurityBehavior(); + } + } +} \ No newline at end of file diff --git a/Service/ServiceBehavior/AdminServiceMessageInspector.cs b/Service/ServiceBehavior/AdminServiceMessageInspector.cs new file mode 100644 index 000000000..592a032b5 --- /dev/null +++ b/Service/ServiceBehavior/AdminServiceMessageInspector.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.ServiceModel.Channels; +using System.ServiceModel.Dispatcher; +using System.ServiceModel; +using System.Text; +using System.Threading.Tasks; +using BeWo.Data; + +namespace BeWo.Service.ServiceBehavior +{ + public class AdminServiceMessageInspector : IDispatchMessageInspector + { + public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) + { + // Hole die erlaubte IP aus den appSettings + string allowedIP = ConfigurationManager.AppSettings["AdminServiceIPAddress"]; + + // Extrahiere die RemoteEndpoint-IP-Adresse + string remoteIP = request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name) + ? ((RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name]).Address + : null; + + // Vergleiche die IPs + if (remoteIP == null || !string.Equals(remoteIP, allowedIP, StringComparison.OrdinalIgnoreCase)) + { + throw new UnauthorizedAccessException($"Zugriff verweigert. Remote IP ({remoteIP ?? "Unbekannt"}) ist nicht erlaubt."); + } + + return null; // Keine Zustandsinformationen erforderlich + } + + public void BeforeSendReply(ref Message reply, object correlationState) + { + // Keine zusätzliche Logik erforderlich vor dem Senden der Antwort + } + } +} diff --git a/Service/ServiceContracts/IAdminService.cs b/Service/ServiceContracts/IAdminService.cs new file mode 100644 index 000000000..ea7a62acd --- /dev/null +++ b/Service/ServiceContracts/IAdminService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel; +using System.ServiceModel.Web; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceContracts +{ + [ServiceContract] + public interface IAdminService + { + [OperationContract] + [WebGet(UriTemplate = "/Test")] + string Test(); + } +} diff --git a/Service/ServiceImplementations/AdminServiceImp.cs b/Service/ServiceImplementations/AdminServiceImp.cs new file mode 100644 index 000000000..9a6566323 --- /dev/null +++ b/Service/ServiceImplementations/AdminServiceImp.cs @@ -0,0 +1,19 @@ +using BeWo.Service.ServiceContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceImplementations +{ + [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)] + public class AdminServiceImp : IAdminService + { + public string Test() + { + return "Test erfolgreich!"; + } + } +}