mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	add a security module (#628) (#629)
* Add security mechanisms, IP whitelists, blacklists, and extended security interfaces. * Optimized configuration name * Fix IP Security Bug * Repair Security Protection Module Bug * Add security module unit test * Optimize log prompts
This commit is contained in:
		@@ -38,7 +38,7 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
        private List<AddHeader> _addHeadersToDownstream;
 | 
			
		||||
        private List<AddHeader> _addHeadersToUpstream;
 | 
			
		||||
        private bool _dangerousAcceptAnyServerCertificateValidator;
 | 
			
		||||
 | 
			
		||||
        private SecurityOptions _securityOptions;
 | 
			
		||||
        public DownstreamReRouteBuilder()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamAddresses = new List<DownstreamHostAndPort>();
 | 
			
		||||
@@ -227,6 +227,12 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DownstreamReRouteBuilder WithSecurityOptions(SecurityOptions securityOptions)
 | 
			
		||||
        {
 | 
			
		||||
            _securityOptions = securityOptions;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DownstreamReRoute Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new DownstreamReRoute(
 | 
			
		||||
@@ -258,7 +264,8 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
                _delegatingHandlers,
 | 
			
		||||
                _addHeadersToDownstream,
 | 
			
		||||
                _addHeadersToUpstream,
 | 
			
		||||
                _dangerousAcceptAnyServerCertificateValidator);
 | 
			
		||||
                _dangerousAcceptAnyServerCertificateValidator,
 | 
			
		||||
                _securityOptions);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								src/Ocelot/Configuration/Creator/ISecurityOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Configuration/Creator/ISecurityOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface ISecurityOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        SecurityOptions Create(FileSecurityOptions securityOptions);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -21,6 +21,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        private readonly IHeaderFindAndReplaceCreator _headerFAndRCreator;
 | 
			
		||||
        private readonly IDownstreamAddressesCreator _downstreamAddressesCreator;
 | 
			
		||||
        private readonly IReRouteKeyCreator _reRouteKeyCreator;
 | 
			
		||||
        private readonly ISecurityOptionsCreator _securityOptionsCreator;
 | 
			
		||||
 | 
			
		||||
        public ReRoutesCreator(
 | 
			
		||||
            IClaimsToThingCreator claimsToThingCreator,
 | 
			
		||||
@@ -35,7 +36,8 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            IHeaderFindAndReplaceCreator headerFAndRCreator,
 | 
			
		||||
            IDownstreamAddressesCreator downstreamAddressesCreator,
 | 
			
		||||
            ILoadBalancerOptionsCreator loadBalancerOptionsCreator,
 | 
			
		||||
            IReRouteKeyCreator reRouteKeyCreator
 | 
			
		||||
            IReRouteKeyCreator reRouteKeyCreator,
 | 
			
		||||
            ISecurityOptionsCreator securityOptionsCreator
 | 
			
		||||
            )
 | 
			
		||||
        {
 | 
			
		||||
            _reRouteKeyCreator = reRouteKeyCreator;
 | 
			
		||||
@@ -52,6 +54,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            _fileReRouteOptionsCreator = fileReRouteOptionsCreator;
 | 
			
		||||
            _httpHandlerOptionsCreator = httpHandlerOptionsCreator;
 | 
			
		||||
            _loadBalancerOptionsCreator = loadBalancerOptionsCreator;
 | 
			
		||||
            _securityOptionsCreator = securityOptionsCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<ReRoute> Create(FileConfiguration fileConfiguration)
 | 
			
		||||
@@ -97,6 +100,8 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
 | 
			
		||||
            var lbOptions = _loadBalancerOptionsCreator.Create(fileReRoute.LoadBalancerOptions);
 | 
			
		||||
 | 
			
		||||
            var securityOptions = _securityOptionsCreator.Create(fileReRoute.SecurityOptions);
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithKey(fileReRoute.Key)
 | 
			
		||||
                .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
 | 
			
		||||
@@ -128,6 +133,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
 | 
			
		||||
                .WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream)
 | 
			
		||||
                .WithDangerousAcceptAnyServerCertificateValidator(fileReRoute.DangerousAcceptAnyServerCertificateValidator)
 | 
			
		||||
                .WithSecurityOptions(securityOptions)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            return reRoute;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								src/Ocelot/Configuration/Creator/SecurityOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/Ocelot/Configuration/Creator/SecurityOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class SecurityOptionsCreator : ISecurityOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        public SecurityOptions Create(FileSecurityOptions securityOptions)
 | 
			
		||||
        {
 | 
			
		||||
            return new SecurityOptions(securityOptions.IPAllowedList, securityOptions.IPBlockedList);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -35,7 +35,8 @@ namespace Ocelot.Configuration
 | 
			
		||||
            List<string> delegatingHandlers,
 | 
			
		||||
            List<AddHeader> addHeadersToDownstream,
 | 
			
		||||
            List<AddHeader> addHeadersToUpstream,
 | 
			
		||||
            bool dangerousAcceptAnyServerCertificateValidator)
 | 
			
		||||
            bool dangerousAcceptAnyServerCertificateValidator,
 | 
			
		||||
            SecurityOptions securityOptions)
 | 
			
		||||
        {
 | 
			
		||||
            DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
 | 
			
		||||
            AddHeadersToDownstream = addHeadersToDownstream;
 | 
			
		||||
@@ -66,6 +67,7 @@ namespace Ocelot.Configuration
 | 
			
		||||
            DownstreamPathTemplate = downstreamPathTemplate;
 | 
			
		||||
            LoadBalancerKey = loadBalancerKey;
 | 
			
		||||
            AddHeadersToUpstream = addHeadersToUpstream;
 | 
			
		||||
            SecurityOptions = securityOptions;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Key { get; }
 | 
			
		||||
@@ -97,5 +99,6 @@ namespace Ocelot.Configuration
 | 
			
		||||
        public List<AddHeader> AddHeadersToDownstream { get; }
 | 
			
		||||
        public List<AddHeader> AddHeadersToUpstream { get; }
 | 
			
		||||
        public bool DangerousAcceptAnyServerCertificateValidator { get; }
 | 
			
		||||
        public SecurityOptions SecurityOptions { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ namespace Ocelot.Configuration.File
 | 
			
		||||
            DownstreamHostAndPorts = new List<FileHostAndPort>();
 | 
			
		||||
            DelegatingHandlers = new List<string>();
 | 
			
		||||
            LoadBalancerOptions = new FileLoadBalancerOptions();
 | 
			
		||||
            SecurityOptions = new FileSecurityOptions();
 | 
			
		||||
            Priority = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -50,5 +51,6 @@ namespace Ocelot.Configuration.File
 | 
			
		||||
        public int Priority { get;set; }
 | 
			
		||||
        public int Timeout { get; set; }
 | 
			
		||||
        public bool DangerousAcceptAnyServerCertificateValidator { get; set; }
 | 
			
		||||
        public FileSecurityOptions SecurityOptions { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								src/Ocelot/Configuration/File/FileSecurityOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Ocelot/Configuration/File/FileSecurityOptions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.File
 | 
			
		||||
{
 | 
			
		||||
    public class FileSecurityOptions
 | 
			
		||||
    {
 | 
			
		||||
        public FileSecurityOptions()
 | 
			
		||||
        {
 | 
			
		||||
            IPAllowedList = new List<string>();
 | 
			
		||||
            IPBlockedList = new List<string>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<string> IPAllowedList { get; set; } 
 | 
			
		||||
 | 
			
		||||
        public List<string> IPBlockedList { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/Ocelot/Configuration/SecurityOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Ocelot/Configuration/SecurityOptions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class SecurityOptions
 | 
			
		||||
    {
 | 
			
		||||
        public SecurityOptions(List<string> allowedList, List<string> blockedList)
 | 
			
		||||
        {
 | 
			
		||||
            this.IPAllowedList = allowedList;
 | 
			
		||||
            this.IPBlockedList = blockedList;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<string> IPAllowedList { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public List<string> IPBlockedList { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -35,6 +35,8 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
    using Ocelot.Infrastructure;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using Ocelot.Request.Creator;
 | 
			
		||||
    using Ocelot.Security.IPSecurity;
 | 
			
		||||
    using Ocelot.Security;
 | 
			
		||||
 | 
			
		||||
    public class OcelotBuilder : IOcelotBuilder
 | 
			
		||||
    {
 | 
			
		||||
@@ -125,6 +127,9 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
            Services.TryAddSingleton<IQoSFactory, QoSFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IExceptionToErrorMapper, HttpExeptionToErrorMapper>();
 | 
			
		||||
 | 
			
		||||
            //add security 
 | 
			
		||||
            this.AddSecurity();
 | 
			
		||||
 | 
			
		||||
            //add asp.net services..
 | 
			
		||||
            var assembly = typeof(FileConfigurationController).GetTypeInfo().Assembly;
 | 
			
		||||
 | 
			
		||||
@@ -139,22 +144,28 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
            Services.AddWebEncoders();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddSingletonDefinedAggregator<T>() 
 | 
			
		||||
        public IOcelotBuilder AddSingletonDefinedAggregator<T>()
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            Services.AddSingleton<IDefinedAggregator, T>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddTransientDefinedAggregator<T>() 
 | 
			
		||||
        public IOcelotBuilder AddTransientDefinedAggregator<T>()
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            Services.AddTransient<IDefinedAggregator, T>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddDelegatingHandler<THandler>(bool global = false) 
 | 
			
		||||
            where THandler : DelegatingHandler 
 | 
			
		||||
        private void AddSecurity()
 | 
			
		||||
        {
 | 
			
		||||
            Services.TryAddSingleton<ISecurityOptionsCreator, SecurityOptionsCreator>();
 | 
			
		||||
            Services.TryAddSingleton<ISecurityPolicy, IPSecurityPolicy>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddDelegatingHandler<THandler>(bool global = false)
 | 
			
		||||
            where THandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            if(global)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Requester.Middleware;
 | 
			
		||||
using Ocelot.RequestId.Middleware;
 | 
			
		||||
using Ocelot.Responder.Middleware;
 | 
			
		||||
using Ocelot.Security.Middleware;
 | 
			
		||||
using Ocelot.WebSockets.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Middleware.Pipeline
 | 
			
		||||
@@ -48,6 +49,9 @@ namespace Ocelot.Middleware.Pipeline
 | 
			
		||||
            // Then we get the downstream route information
 | 
			
		||||
            builder.UseDownstreamRouteFinderMiddleware();
 | 
			
		||||
 | 
			
		||||
            // This security module, IP whitelist blacklist, extended security mechanism
 | 
			
		||||
            builder.UseSecurityMiddleware();
 | 
			
		||||
 | 
			
		||||
            //Expand other branch pipes
 | 
			
		||||
            if (pipelineConfiguration.MapWhenOcelotPipeline != null)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								src/Ocelot/Security/IPSecurity/IPSecurityPolicy.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/Ocelot/Security/IPSecurity/IPSecurityPolicy.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Security.IPSecurity
 | 
			
		||||
{
 | 
			
		||||
    public class IPSecurityPolicy : ISecurityPolicy
 | 
			
		||||
    {
 | 
			
		||||
        public async Task<Response> Security(DownstreamContext context)
 | 
			
		||||
        {
 | 
			
		||||
            IPAddress clientIp = context.HttpContext.Connection.RemoteIpAddress;
 | 
			
		||||
            SecurityOptions securityOptions = context.DownstreamReRoute.SecurityOptions;
 | 
			
		||||
            if (securityOptions == null)
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (securityOptions.IPBlockedList != null)
 | 
			
		||||
            {
 | 
			
		||||
                if (securityOptions.IPBlockedList.Exists(f => f == clientIp.ToString()))
 | 
			
		||||
                {
 | 
			
		||||
                    var error = new UnauthenticatedError($" This request rejects access to {clientIp.ToString()} IP");
 | 
			
		||||
                    return new ErrorResponse(error);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (securityOptions.IPAllowedList != null && securityOptions.IPAllowedList.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                if (!securityOptions.IPAllowedList.Exists(f => f == clientIp.ToString()))
 | 
			
		||||
                {
 | 
			
		||||
                    var error = new UnauthenticatedError($"{clientIp.ToString()} does not allow access, the request is invalid");
 | 
			
		||||
                    return new ErrorResponse(error);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
         
 | 
			
		||||
            return await Task.FromResult(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/Ocelot/Security/ISecurityPolicy.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/Ocelot/Security/ISecurityPolicy.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Security
 | 
			
		||||
{
 | 
			
		||||
    public interface ISecurityPolicy
 | 
			
		||||
    {
 | 
			
		||||
        Task<Response> Security(DownstreamContext context);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								src/Ocelot/Security/Middleware/SecurityMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/Ocelot/Security/Middleware/SecurityMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Security.Middleware
 | 
			
		||||
{
 | 
			
		||||
    public class SecurityMiddleware : OcelotMiddleware
 | 
			
		||||
    {
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly IEnumerable<ISecurityPolicy> _securityPolicies;
 | 
			
		||||
        public SecurityMiddleware(IOcelotLoggerFactory loggerFactory,
 | 
			
		||||
            IEnumerable<ISecurityPolicy> securityPolicies,
 | 
			
		||||
            OcelotRequestDelegate next)
 | 
			
		||||
            : base(loggerFactory.CreateLogger<SecurityMiddleware>())
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<SecurityMiddleware>();
 | 
			
		||||
            _securityPolicies = securityPolicies;
 | 
			
		||||
            _next = next;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task Invoke(DownstreamContext context)
 | 
			
		||||
        {
 | 
			
		||||
            if (_securityPolicies != null)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var policie in _securityPolicies)
 | 
			
		||||
                {
 | 
			
		||||
                    var result = await policie.Security(context);
 | 
			
		||||
                    if (!result.IsError)
 | 
			
		||||
                    {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    this.SetPipelineError(context, result.Errors);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await _next.Invoke(context);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
using Ocelot.Middleware.Pipeline;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Security.Middleware
 | 
			
		||||
{
 | 
			
		||||
    public static class SecurityMiddlewareExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static IOcelotPipelineBuilder UseSecurityMiddleware(this IOcelotPipelineBuilder builder)
 | 
			
		||||
        {
 | 
			
		||||
            return builder.UseMiddleware<SecurityMiddleware>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user