Refactor: Attribute
Weniger Unklarheit bzgl Abfragen bei jeweiligen Service Endpunkten
This commit is contained in:
22
Service/Attributes/RequireApiAuthorizationAttribute.cs
Normal file
22
Service/Attributes/RequireApiAuthorizationAttribute.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using BS.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BeWo.Service.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
|
||||
public class RequireApiAuthorizationAttribute : Attribute
|
||||
{
|
||||
public RequireApiAuthorizationAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public WebSecretConfigSetting ApiKeyName { get; set; } = WebSecretConfigSetting.None;
|
||||
public IPAddressList IPAddressList { get; set; } = IPAddressList.None;
|
||||
public bool IgnoreTenant { get; set; } = false;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BeWo.Service.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
|
||||
public class RequireApiKeyAttribute : Attribute
|
||||
{
|
||||
public WebSecretConfigSetting ApiKeyName { get; set; }
|
||||
|
||||
public RequireApiKeyAttribute(WebSecretConfigSetting api_key_name)
|
||||
{
|
||||
ApiKeyName = api_key_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BeWo.Service.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
|
||||
public class RequireIPAddressAttribute : Attribute
|
||||
{
|
||||
//public List<string> AllowedIPs { get; set; }
|
||||
public IPAddressList IPAddressList { get; set; }
|
||||
|
||||
//public RequireIPAddressAttribute(List<string> allowed_ips)
|
||||
//{
|
||||
// AllowedIPs = allowed_ips;
|
||||
//}
|
||||
|
||||
//public RequireIPAddressAttribute(string allowedIP) : this(new List<string>() { allowedIP }) { }
|
||||
|
||||
public RequireIPAddressAttribute(IPAddressList iPAddressList)
|
||||
{
|
||||
IPAddressList = iPAddressList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BeWo.Service.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
|
||||
public class RequireNoTenantAttribute : Attribute
|
||||
{
|
||||
public RequireNoTenantAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
using System;
|
||||
using BS.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BS.Shared;
|
||||
|
||||
namespace BeWo.Service.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
|
||||
public class RequirePermissionAttribute : Attribute
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
|
||||
public class RequireWcfAuthorizationAttribute : Attribute
|
||||
{
|
||||
public UserRightType[] Permissions { get; }
|
||||
|
||||
public RequirePermissionAttribute(params UserRightType[] permissions)
|
||||
public RequireWcfAuthorizationAttribute(params UserRightType[] pPermissions)
|
||||
{
|
||||
Permissions = permissions;
|
||||
Permissions = pPermissions;
|
||||
}
|
||||
|
||||
public UserRightType[] Permissions { get; }
|
||||
|
||||
public bool HasPermission(IEnumerable<UserRightType> rights)
|
||||
{
|
||||
if (Permissions is null || Permissions.Length == 0)
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -19,8 +20,10 @@ namespace BeWo.Service
|
||||
ApiServiceTestFilePath
|
||||
}
|
||||
|
||||
[DefaultValue(None)]
|
||||
public enum WebSecretConfigSetting
|
||||
{
|
||||
None = -1,
|
||||
OpenWebUIKey,
|
||||
GetGkvSumApiKey,
|
||||
DownloadReportApiKey,
|
||||
@@ -29,8 +32,10 @@ namespace BeWo.Service
|
||||
GkvSecretKey,
|
||||
}
|
||||
|
||||
[DefaultValue(None)]
|
||||
public enum IPAddressList
|
||||
{
|
||||
None = -1,
|
||||
AdminApi
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace BeWo.Service.Core
|
||||
{
|
||||
public static List<string> GetIPAddressList(IPAddressList iPAddressList)
|
||||
{
|
||||
if(iPAddressList == IPAddressList.None)
|
||||
throw new ArgumentException(nameof(iPAddressList));
|
||||
|
||||
var lConfigPath = iPAddressList.GetConfigPath();
|
||||
|
||||
var lines = File.ReadAllLines(lConfigPath);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using BeWo.Data.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
@@ -18,6 +19,9 @@ namespace BeWo.Service.Core
|
||||
|
||||
public static string GetSecretSetting(WebSecretConfigSetting webSecretConfigSetting)
|
||||
{
|
||||
if (webSecretConfigSetting == WebSecretConfigSetting.None)
|
||||
throw new ArgumentNullException("webSecretConfigSetting");
|
||||
|
||||
return getSecretSetting(webSecretConfigSetting.ToString());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
using BeWo.Service.Attributes;
|
||||
using BeWo.Service.ServiceUtils;
|
||||
using BS.Shared.Extensions;
|
||||
|
||||
namespace BeWo.Service.Core
|
||||
{
|
||||
@@ -13,7 +16,14 @@ namespace BeWo.Service.Core
|
||||
public static FileLogger WCFErrorLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.ServiceLogFilePath));
|
||||
public static FileLogger JsonErrorLogger { get; } = new FileLogger(MergedConfig.GetSetting(WebConfigSetting.ServiceLogFilePath));
|
||||
|
||||
public static Tuple<string, string> GetInterfaceAndMethodASP(Message request , IClientChannel channel)
|
||||
public static Tuple<string, string> GetInterfaceAndMethodWCF(Message request, IClientChannel channel)
|
||||
{
|
||||
var lTemp = request.Headers.Action.Split("/");
|
||||
string lMethodName = lTemp[lTemp.Count - 1];
|
||||
string lServiceInterface = lTemp[lTemp.Count - 2];
|
||||
return new Tuple<string, string>(lServiceInterface, lMethodName);
|
||||
}
|
||||
public static Tuple<string, string> GetInterfaceAndMethodASP(Message request, IClientChannel channel)
|
||||
{
|
||||
// Hole Interface
|
||||
string lInterface = null;
|
||||
@@ -59,7 +69,7 @@ namespace BeWo.Service.Core
|
||||
}
|
||||
|
||||
// Falls kein Interface gefunden wird
|
||||
if (string.IsNullOrWhiteSpace(lInterface) )
|
||||
if (string.IsNullOrWhiteSpace(lInterface))
|
||||
{
|
||||
throw new ArgumentException($"Zugriff verweigert. Interface unbekannt");
|
||||
}
|
||||
@@ -75,6 +85,12 @@ namespace BeWo.Service.Core
|
||||
return getCustomAttribute<T>(methodInfo);
|
||||
}
|
||||
|
||||
public static T GetCustomAttribute<T>(Message request, IClientChannel channel) where T : Attribute
|
||||
{
|
||||
var (inter, method) = GetInterfaceAndMethodASP(request, channel);
|
||||
var authentification = GetCustomAttribute<T>(inter, method);
|
||||
return authentification;
|
||||
}
|
||||
public static T GetCustomAttribute<T>(string pServiceInterface, string pMethodName) where T : Attribute
|
||||
{
|
||||
MethodInfo methodInfo = null;
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
using BS.Shared.DataContracts;
|
||||
using BeWo.Data;
|
||||
using BeWo.Service.Attributes;
|
||||
using BS.Shared;
|
||||
using BS.Shared.DataContracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
using System.Runtime.Serialization;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -34,5 +40,107 @@ namespace BeWo.Service.Core
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ValidateConnection(ref Message request, IClientChannel channel)
|
||||
{
|
||||
var authentification = ServiceHelper.GetCustomAttribute<RequireApiAuthorizationAttribute>(request, channel);
|
||||
|
||||
if (authentification is null)
|
||||
return;
|
||||
|
||||
if (authentification.IPAddressList is IPAddressList ipAddressList && ipAddressList != default)
|
||||
ValidateIP(ref request, channel, ipAddressList);
|
||||
|
||||
if (authentification.ApiKeyName is WebSecretConfigSetting secret && secret != default)
|
||||
ValidateMethodApiKey(ref request, channel, secret);
|
||||
}
|
||||
|
||||
public static object ValidateTenant(ref Message request, IClientChannel channel)
|
||||
{
|
||||
var authentification = ServiceHelper.GetCustomAttribute<RequireApiAuthorizationAttribute>(request, channel);
|
||||
|
||||
if (authentification is object && authentification.IgnoreTenant)
|
||||
return null;
|
||||
|
||||
string lTenant = null;
|
||||
|
||||
// Hole tenant aus Header
|
||||
var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
|
||||
lTenant = prop?.Headers["tenant"];
|
||||
|
||||
// Wenn kein Tenant gefunden wird,
|
||||
if (string.IsNullOrWhiteSpace(lTenant))
|
||||
{
|
||||
throw new ArgumentException($"Zugriff verweigert. Tenant (\'{lTenant}\') darf nicht leer sein.", nameof(lTenant));
|
||||
}
|
||||
|
||||
var lExt = new MultitenancyOperationContextExt { Tenant = lTenant };
|
||||
OperationContext.Current.Extensions.Add(lExt);
|
||||
return lExt;
|
||||
}
|
||||
|
||||
private static void ValidateIP(ref Message request, IClientChannel channel, IPAddressList ipAddressList)
|
||||
{
|
||||
// Extrahiere die RemoteEndpoint-IP-Adresse
|
||||
string remoteIP = request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)
|
||||
? ((RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name]).Address
|
||||
: null;
|
||||
|
||||
if (remoteIP == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Remote IP (\"null\") ist nicht erlaubt.");
|
||||
}
|
||||
|
||||
var allowedIPs = ConfigReader.GetIPAddressList(ipAddressList);
|
||||
|
||||
if (allowedIPs is null || allowedIPs.Count == 0)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Konfigurationsfehler.");
|
||||
}
|
||||
|
||||
if (allowedIPs.All(x => !string.Equals(remoteIP, x, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Remote IP ({remoteIP}) ist nicht erlaubt.");
|
||||
}
|
||||
}
|
||||
|
||||
//public void ValidateServiceApiKey(ref Message request)
|
||||
//{
|
||||
// //// Hole erlaubten API Key aus den appSettings
|
||||
// //string allowedApikey = MergedConfig.GetSecretSetting(WebSecretConfigSetting.AdminServiceAPIKey);
|
||||
|
||||
// //// Extrahiert den API Key von Remote
|
||||
// //var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
|
||||
// //var remoteApikey = prop?.Headers["admin-service-api-key"];
|
||||
|
||||
// //// Vergleicht die API Keys
|
||||
// //if (remoteApikey == null || !string.Equals(remoteApikey, allowedApikey, StringComparison.Ordinal))
|
||||
// //{
|
||||
// // throw new UnauthorizedAccessException($"Zugriff verweigert. API Key ({remoteApikey ?? "Unbekannt"}) ist nicht erlaubt.");
|
||||
// //}
|
||||
//}
|
||||
|
||||
private static void ValidateMethodApiKey(ref Message request, IClientChannel channel, WebSecretConfigSetting secret)
|
||||
{
|
||||
// Hole erlaubten API Key aus den appSettings
|
||||
string allowedApikey = MergedConfig.GetSecretSetting(secret);
|
||||
|
||||
if (string.IsNullOrEmpty(allowedApikey))
|
||||
{
|
||||
return;
|
||||
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Api Key kann nicht geladen werden.");
|
||||
}
|
||||
|
||||
// Extrahiert den API Key von Remote
|
||||
var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
|
||||
var remoteApikey = prop?.Headers[secret.ToString()];
|
||||
|
||||
// Vergleicht die API Keys
|
||||
if (remoteApikey == null || !string.Equals(remoteApikey, allowedApikey, StringComparison.Ordinal))
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. API Key ({remoteApikey ?? "Unbekannt"}) ist nicht erlaubt.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
@@ -13,6 +14,7 @@ using BeWo.Service.Attributes;
|
||||
using BeWo.Service.Core;
|
||||
using BS.Shared.DataContracts;
|
||||
using BS.Shared.Extensions;
|
||||
using DevExpress.Charts.Native;
|
||||
|
||||
namespace BeWo.Service.Security
|
||||
{
|
||||
@@ -63,54 +65,34 @@ namespace BeWo.Service.Security
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
|
||||
var lTemp = pMessage.Headers.Action.Split("/");
|
||||
string lMethodName = lTemp[lTemp.Count - 1];
|
||||
string lServiceInterface = lTemp[lTemp.Count - 2];
|
||||
var (lServiceInterface, lMethodName) = ServiceHelper.GetInterfaceAndMethodWCF(pMessage, pChannel);
|
||||
|
||||
// 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 < 0)
|
||||
throw new SecurityException("Nicht autorisiert");
|
||||
|
||||
if (lSecurityHeaderIndex > -1)
|
||||
{
|
||||
XmlReader lReader = pMessage.Headers.GetReaderAtHeader(lSecurityHeaderIndex);
|
||||
XmlReader lReader = pMessage.Headers.GetReaderAtHeader(lSecurityHeaderIndex);
|
||||
|
||||
if (lReader.ReadToFollowing("Username"))
|
||||
{
|
||||
lUserName = lReader.ReadString();
|
||||
}
|
||||
string lUserName = null, lPassword = null;
|
||||
if (lReader.ReadToFollowing("Username"))
|
||||
lUserName = lReader.ReadString();
|
||||
if (lReader.ReadToFollowing("Password"))
|
||||
lPassword = lReader.ReadString();
|
||||
|
||||
if (lReader.ReadToFollowing("Password"))
|
||||
{
|
||||
lPassword = lReader.ReadString();
|
||||
}
|
||||
ApplicationUser lUser = DAOFactory.UserDAO.FindUserByLoginName(lUserName);
|
||||
|
||||
ApplicationUser lUser = DAOFactory.UserDAO.FindUserByLoginName(lUserName);
|
||||
if (lUser == null || !DAOFactory.UserDAO.CheckPassword(lUser, lPassword))
|
||||
throw new SecurityException("Nicht autorisiert");
|
||||
|
||||
if (lUser != null && DAOFactory.UserDAO.CheckPassword(lUser, lPassword))
|
||||
{
|
||||
if (!HasMethodAuthorization(lUser, lMethodName, pMessage))
|
||||
{
|
||||
throw new SecurityException("Methode nicht autorisiert: " + lMethodName);
|
||||
}
|
||||
if (!HasMethodAuthorization(lUser, lServiceInterface, lMethodName))
|
||||
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");
|
||||
var lExt = new LoggedInUserOperationContextExt { User = lUser, LoginName = lUserName, UnhashedPassword = lPassword };
|
||||
OperationContext.Current.Extensions.Add(lExt);
|
||||
return lExt;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -118,39 +100,19 @@ namespace BeWo.Service.Security
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasMethodAuthorization(ApplicationUser pUser, string methodName, Message pMessage)
|
||||
private bool HasMethodAuthorization(ApplicationUser pUser, string pServiceInterface, string pMethodName)
|
||||
{
|
||||
if (ALLOW_ONLY_WITH_LOGIN.Contains(methodName))
|
||||
{
|
||||
if (ALLOW_ONLY_WITH_LOGIN.Contains(pMethodName))
|
||||
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<RequirePermissionAttribute>(lServiceInterface, lMethodName);
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute.HasPermission(rights);
|
||||
}
|
||||
var attribute = ServiceHelper.GetCustomAttribute<RequireWcfAuthorizationAttribute>(pServiceInterface, pMethodName);
|
||||
if (attribute is null)
|
||||
return true;
|
||||
|
||||
var rights = Utils.GetGrantedRights(pUser);
|
||||
return attribute.HasPermission(rights);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -159,6 +121,5 @@ namespace BeWo.Service.Security
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,10 +224,8 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Attributes\RequireApiKeyAttribute.cs" />
|
||||
<Compile Include="Attributes\RequireIPAddressAttribute.cs" />
|
||||
<Compile Include="Attributes\RequireNoTenantAttribute.cs" />
|
||||
<Compile Include="Attributes\RequirePermissionAttribute.cs" />
|
||||
<Compile Include="Attributes\RequireWcfAuthorizationAttribute.cs" />
|
||||
<Compile Include="Attributes\RequireApiAuthorizationAttribute.cs" />
|
||||
<Compile Include="BeWoServiceEnums.cs" />
|
||||
<Compile Include="Core\ConfigReader.cs" />
|
||||
<Compile Include="Core\DiamantExporter.cs" />
|
||||
|
||||
@@ -29,43 +29,7 @@ namespace BeWo.Service.ServiceBehavior
|
||||
|
||||
public object BeforeInvoke(InstanceContext pInstanceContext, IClientChannel pChannel, Message pMessage)
|
||||
{
|
||||
string lTenant = null;
|
||||
|
||||
var (lInterface, lMethod) = ServiceHelper.GetInterfaceAndMethodASP(pMessage, pChannel);
|
||||
|
||||
var lTemp = ServiceHelper.GetCustomAttribute<RequireNoTenantAttribute>(lInterface, lMethod);
|
||||
if (lTemp is object)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Hole tenant aus Query
|
||||
// Wird erstmal nicht benötigt. Per Header besser
|
||||
// Ungefähr auf einem Level wie Username
|
||||
//if (pMessage.Properties?.Via is Uri uri)
|
||||
//{
|
||||
// var query = HttpUtility.ParseQueryString(uri.Query);
|
||||
// var tenant = query["tenant"];
|
||||
|
||||
// lTenant = tenant;
|
||||
//}
|
||||
|
||||
// Hole tenant aus Header
|
||||
if (string.IsNullOrWhiteSpace(lTenant))
|
||||
{
|
||||
var prop = (HttpRequestMessageProperty)pMessage.Properties[HttpRequestMessageProperty.Name];
|
||||
lTenant = prop?.Headers["tenant"];
|
||||
}
|
||||
|
||||
// Wenn kein Tenant gefunden wird,
|
||||
if (string.IsNullOrWhiteSpace(lTenant))
|
||||
{
|
||||
throw new ArgumentException($"Zugriff verweigert. Tenant (\'{lTenant}\') darf nicht leer sein.", nameof(lTenant));
|
||||
}
|
||||
|
||||
var lExt = new MultitenancyOperationContextExt { Tenant = lTenant };
|
||||
OperationContext.Current.Extensions.Add(lExt);
|
||||
return lExt;
|
||||
return ServiceValidator.ValidateTenant(ref pMessage, pChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace BeWo.Service.ServiceBehavior
|
||||
{
|
||||
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
|
||||
{
|
||||
ValidateIP(ref request, channel);
|
||||
|
||||
ValidateApiKey(ref request, channel);
|
||||
ServiceValidator.ValidateConnection(ref request, channel);
|
||||
|
||||
return null; // Keine Zustandsinformationen erforderlich
|
||||
}
|
||||
@@ -31,91 +29,5 @@ namespace BeWo.Service.ServiceBehavior
|
||||
{
|
||||
// Keine zusätzliche Logik erforderlich vor dem Senden der Antwort
|
||||
}
|
||||
|
||||
public void ValidateIP(ref Message request, IClientChannel channel)
|
||||
{
|
||||
var (inter, method) = ServiceHelper.GetInterfaceAndMethodASP(request, channel);
|
||||
|
||||
var attr = ServiceHelper.GetCustomAttribute<RequireIPAddressAttribute>(inter, method);
|
||||
|
||||
if (attr is null)
|
||||
return;
|
||||
|
||||
// Extrahiere die RemoteEndpoint-IP-Adresse
|
||||
string remoteIP = request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)
|
||||
? ((RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name]).Address
|
||||
: null;
|
||||
|
||||
if (remoteIP == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Remote IP ({remoteIP ?? "Unbekannt"}) ist nicht erlaubt.");
|
||||
}
|
||||
|
||||
var ipList = attr.IPAddressList;
|
||||
var allowedIPs = ConfigReader.GetIPAddressList(ipList);
|
||||
|
||||
if(allowedIPs is null ||allowedIPs.Count == 0)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Konfigurationsfehler.");
|
||||
}
|
||||
|
||||
if(allowedIPs.All(x => !string.Equals(remoteIP, x, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Remote IP ({remoteIP ?? "Unbekannt"}) ist nicht erlaubt.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ValidateApiKey(ref Message request, IClientChannel channel)
|
||||
{
|
||||
ValidateMethodApiKey(ref request, channel);
|
||||
}
|
||||
|
||||
//public void ValidateServiceApiKey(ref Message request)
|
||||
//{
|
||||
// //// Hole erlaubten API Key aus den appSettings
|
||||
// //string allowedApikey = MergedConfig.GetSecretSetting(WebSecretConfigSetting.AdminServiceAPIKey);
|
||||
|
||||
// //// Extrahiert den API Key von Remote
|
||||
// //var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
|
||||
// //var remoteApikey = prop?.Headers["admin-service-api-key"];
|
||||
|
||||
// //// Vergleicht die API Keys
|
||||
// //if (remoteApikey == null || !string.Equals(remoteApikey, allowedApikey, StringComparison.Ordinal))
|
||||
// //{
|
||||
// // throw new UnauthorizedAccessException($"Zugriff verweigert. API Key ({remoteApikey ?? "Unbekannt"}) ist nicht erlaubt.");
|
||||
// //}
|
||||
//}
|
||||
|
||||
public void ValidateMethodApiKey(ref Message request, IClientChannel channel)
|
||||
{
|
||||
var (inter, method) = ServiceHelper.GetInterfaceAndMethodASP(request, channel);
|
||||
|
||||
var attr = ServiceHelper.GetCustomAttribute<RequireApiKeyAttribute>(inter, method);
|
||||
|
||||
if (attr is null)
|
||||
return;
|
||||
|
||||
var api_key_name = attr.ApiKeyName;
|
||||
|
||||
// Hole erlaubten API Key aus den appSettings
|
||||
string allowedApikey = MergedConfig.GetSecretSetting(api_key_name);
|
||||
|
||||
if (string.IsNullOrEmpty(allowedApikey))
|
||||
{
|
||||
return;
|
||||
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. Api Key kann nicht geladen werden.");
|
||||
}
|
||||
|
||||
// Extrahiert den API Key von Remote
|
||||
var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
|
||||
var remoteApikey = prop?.Headers[api_key_name.ToString()];
|
||||
|
||||
// Vergleicht die API Keys
|
||||
if (remoteApikey == null || !string.Equals(remoteApikey, allowedApikey, StringComparison.Ordinal))
|
||||
{
|
||||
throw new UnauthorizedAccessException($"Zugriff verweigert. API Key ({remoteApikey ?? "Unbekannt"}) ist nicht erlaubt.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,47 +18,47 @@ namespace BeWo.Service.ServiceContracts.Enhanced
|
||||
{
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleView, UserRightType.AiModuleView2)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleView, UserRightType.AiModuleView2)]
|
||||
AiConfigDC GetAiConfig();
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleViewSetting)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleViewSetting)]
|
||||
AiConfigDC UpdateAiConfig(AiConfigDC toUpdate);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleView, UserRightType.AiModuleView2)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleView, UserRightType.AiModuleView2)]
|
||||
IEnumerable<AiModelDC> GetAiModels();
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleView, UserRightType.AiModuleView2)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleView, UserRightType.AiModuleView2)]
|
||||
IEnumerable<AiConversationDC> GetAiConversations(int uicontext, long? oid);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleChatAdd)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleChatAdd)]
|
||||
AiConversationDC CreateAiConversation(AiConversationDC conversation, long modell_oid);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleChatAdd)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleChatAdd)]
|
||||
AiConversationDC CreateAiConversationWithMessage(AiConversationDC conversation, long modell_oid, string message);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleChatClone)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleChatClone)]
|
||||
AiConversationDC CloneAiConversation(long conversation_oid, long? message_oid);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleChatDelete)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleChatDelete)]
|
||||
void DeleteAiConversation(long conversation_oid);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.AiModuleChatAdd)]
|
||||
[RequireWcfAuthorization(UserRightType.AiModuleChatAdd)]
|
||||
AiConversationMessageDC[] SendNewMessage(long conversation, string message);
|
||||
}
|
||||
}
|
||||
@@ -15,17 +15,17 @@ namespace BeWo.Service.ServiceContracts
|
||||
{
|
||||
[OperationContract]
|
||||
[WebGet(UriTemplate = "/Test", ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireNoTenant]
|
||||
[RequireApiAuthorization(IgnoreTenant = true)]
|
||||
string Test();
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(UriTemplate = "/Echo/{echo}", Method ="POST", ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireNoTenant]
|
||||
[RequireApiAuthorization(IgnoreTenant = true)]
|
||||
string Echo(string echo);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(UriTemplate = "/GetGkvSum", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireIPAddress(IPAddressList.AdminApi)]
|
||||
[RequireApiAuthorization(IPAddressList = IPAddressList.AdminApi)]
|
||||
object GetGkvAbrechnungSumme(AdminServiceSumReqDC request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,12 @@ namespace BeWo.Service.ServiceContracts
|
||||
{
|
||||
[OperationContract]
|
||||
[WebGet(UriTemplate = "/Test", ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireNoTenant]
|
||||
[RequireApiAuthorization(IgnoreTenant = true)]
|
||||
ApiResponse<string> Test();
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(UriTemplate = "/GetGkvSum", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireApiKey(WebSecretConfigSetting.GetGkvSumApiKey)]
|
||||
[RequireIPAddress(IPAddressList.AdminApi)]
|
||||
[RequireApiAuthorization(ApiKeyName = WebSecretConfigSetting.GetGkvSumApiKey, IPAddressList = IPAddressList.AdminApi)]
|
||||
ApiResponse<decimal> GetGkvAbrechnungSumme(AdminServiceSumReqDC request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,22 +15,14 @@ namespace BeWo.Service.ServiceContracts
|
||||
[ServiceContract]
|
||||
public interface IApiStreamService
|
||||
{
|
||||
//[OperationContract]
|
||||
//[WebGet(UriTemplate = "/DownloadReport", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
//[RequireApiKey(WebSecretConfigSetting.DownloadReportApiKey)]
|
||||
//[RequireNoTenant]
|
||||
//Stream DownloadReport();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(UriTemplate = "/GetPdf", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireNoTenant]
|
||||
[RequireIPAddress(IPAddressList.AdminApi)]
|
||||
[RequireApiAuthorization(IPAddressList = IPAddressList.AdminApi, IgnoreTenant = true)]
|
||||
Stream GetPdf();
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(UriTemplate = "/GetPdf", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
[RequireNoTenant]
|
||||
[RequireIPAddress(IPAddressList.AdminApi)]
|
||||
[RequireApiAuthorization(IPAddressList = IPAddressList.AdminApi, IgnoreTenant = true)]
|
||||
Stream GetPdf2();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,42 +19,42 @@ namespace BeWo.Service.ServiceContracts
|
||||
{
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_View)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_View)]
|
||||
GkvAbrechnungLightDC GetGkvAbrechnung(long oid);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_View)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_View)]
|
||||
List<GkvAbrechnungLightDC> GetAllGkvAbrechnungen();
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_View)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_View)]
|
||||
List<GkvAbrechnungLightDC> GetAllGkvAbrechnungenBy(GkvAbrechnungViewFilterDC gkvAbrechnungViewFilter);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_View)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_View)]
|
||||
string GetProtokollRawDataString(long oid, GkvRawDataType gkvRawData);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_Create)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_Create)]
|
||||
GkvAbrechnungCreateResponseDC CreateNewGkvAbrechnung(GkvAbrechnungCreateRequestDC request);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_Create)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_Create)]
|
||||
GkvAbrechnungLightDC UpdateGkvAbrechnung(GkvAbrechnungLightDC abrechnung);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_Delete)]
|
||||
void DeleteGkvAbrechnung(long oid, long version);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.Finance_Gkv_Send)]
|
||||
[RequireWcfAuthorization(UserRightType.Finance_Gkv_Send)]
|
||||
GkvAbrechnungSendResponseDC SendNewGkvAbrechnung(GkvAbrechnungSendRequestDC req);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
|
||||
@@ -23,37 +23,37 @@ namespace BeWo.Service.ServiceContracts
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserView_Delete)]
|
||||
void DeactivateUser(long pOid, long pVersion);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserGroupView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserGroupView_Delete)]
|
||||
void DeactivateUserGroup(long pOid, long pVersion);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserView_Delete)]
|
||||
void DeactivateUsers(Dictionary<long, long> pOid2Version);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserView_Delete)]
|
||||
void DeleteUser(long pOid, long pVersion);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserGroupView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserGroupView_Delete)]
|
||||
void DeleteUserGroup(long pOid, long pVersion);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserGroupView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserGroupView_Delete)]
|
||||
void DeleteUserGroups(Dictionary<long, long> pOid2Version);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserView_Delete)]
|
||||
[RequireWcfAuthorization(UserRightType.UserView_Delete)]
|
||||
void DeleteUsers(Dictionary<long, long> pOid2Version);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
@@ -78,12 +78,12 @@ namespace BeWo.Service.ServiceContracts
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserView_Create)]
|
||||
[RequireWcfAuthorization(UserRightType.UserView_Create)]
|
||||
long InsertNewUser(UserDC pUser);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserGroupView_Create)]
|
||||
[RequireWcfAuthorization(UserRightType.UserGroupView_Create)]
|
||||
long InsertNewUserGroup(UserGroupDC pUserGroup);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
@@ -116,7 +116,7 @@ namespace BeWo.Service.ServiceContracts
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
[OperationContract]
|
||||
[RequirePermission(UserRightType.UserGroupView_Edit, UserRightType.EditAll)]
|
||||
[RequireWcfAuthorization(UserRightType.UserGroupView_Edit, UserRightType.EditAll)]
|
||||
long UpdateUserGroup(UserGroupDC pUserGroup);
|
||||
|
||||
[FaultContract(typeof(BeWoFault))]
|
||||
|
||||
Reference in New Issue
Block a user