mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 17:40:50 +08:00 
			
		
		
		
	started adding route authorisation
This commit is contained in:
		@@ -4,5 +4,7 @@ echo Building Ocelot
 | 
			
		||||
dotnet restore src/Ocelot
 | 
			
		||||
dotnet build src/Ocelot
 | 
			
		||||
dotnet publish src/Ocelot -o artifacts/
 | 
			
		||||
dotnet pack src/Ocelot/project.json --output nupkgs/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								src/Ocelot/Authorisation/AuthorisationMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/Ocelot/Authorisation/AuthorisationMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.ScopedData;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public class AuthorisationMiddleware : OcelotMiddleware
 | 
			
		||||
    {
 | 
			
		||||
        private readonly RequestDelegate _next;
 | 
			
		||||
        private readonly IScopedRequestDataRepository _scopedRequestDataRepository;
 | 
			
		||||
        private readonly IAuthoriser _authoriser;
 | 
			
		||||
 | 
			
		||||
        public AuthorisationMiddleware(RequestDelegate next, 
 | 
			
		||||
            IScopedRequestDataRepository scopedRequestDataRepository, 
 | 
			
		||||
            IAuthoriser authoriser)
 | 
			
		||||
            : base(scopedRequestDataRepository)
 | 
			
		||||
        {
 | 
			
		||||
            _next = next;
 | 
			
		||||
            _scopedRequestDataRepository = scopedRequestDataRepository;
 | 
			
		||||
            _authoriser = authoriser;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task Invoke(HttpContext context)
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = _scopedRequestDataRepository.Get<DownstreamRoute>("DownstreamRoute");
 | 
			
		||||
 | 
			
		||||
            if (downstreamRoute.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                SetPipelineError(downstreamRoute.Errors);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var authorised = _authoriser.Authorise(context.User, new RouteClaimsRequirement());
 | 
			
		||||
 | 
			
		||||
            if (authorised)
 | 
			
		||||
            {
 | 
			
		||||
                await _next.Invoke(context);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                //set an error
 | 
			
		||||
                SetPipelineError(new List<Error>
 | 
			
		||||
                {
 | 
			
		||||
                    new UnauthorisedError($"{context.User.Identity.Name} unable to access {downstreamRoute.Data.ReRoute.UpstreamTemplate}")
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public static class AuthorisationMiddlewareMiddlewareExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static IApplicationBuilder UseAuthorisationMiddleware(this IApplicationBuilder builder)
 | 
			
		||||
        {
 | 
			
		||||
            return builder.UseMiddleware<AuthorisationMiddleware>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/Ocelot/Authorisation/ClaimsAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Authorisation/ClaimsAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public class ClaimsAuthoriser : IAuthoriser
 | 
			
		||||
    {
 | 
			
		||||
        public bool Authorise(ClaimsPrincipal claimsPrincipal, RouteClaimsRequirement routeClaimsRequirement)
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								src/Ocelot/Authorisation/IAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Ocelot/Authorisation/IAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public interface IAuthoriser
 | 
			
		||||
    {
 | 
			
		||||
        bool Authorise(ClaimsPrincipal claimsPrincipal, 
 | 
			
		||||
            RouteClaimsRequirement routeClaimsRequirement);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/Ocelot/Authorisation/RouteClaimsRequirement.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Ocelot/Authorisation/RouteClaimsRequirement.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public class RouteClaimsRequirement
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/Ocelot/Authorisation/UnauthorisedError.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Authorisation/UnauthorisedError.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public class UnauthorisedError : Error
 | 
			
		||||
    {
 | 
			
		||||
        public UnauthorisedError(string message) 
 | 
			
		||||
            : base(message, OcelotErrorCode.UnauthorizedError)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.AspNetCore.Authorization;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Authentication.Handler.Creator;
 | 
			
		||||
using Ocelot.Authentication.Handler.Factory;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.Configuration.Creator;
 | 
			
		||||
using Ocelot.Configuration.Parser;
 | 
			
		||||
using Ocelot.Configuration.Provider;
 | 
			
		||||
@@ -45,6 +47,7 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
            services.AddLogging();
 | 
			
		||||
 | 
			
		||||
            // ocelot services.
 | 
			
		||||
            services.AddSingleton<IAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            services.AddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
			
		||||
            services.AddSingleton<IClaimsParser, ClaimsParser>();
 | 
			
		||||
            services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
        CannotFindClaimError,
 | 
			
		||||
        ParsingConfigurationHeaderError,
 | 
			
		||||
        NoInstructionsError,
 | 
			
		||||
        InstructionNotForClaimsError
 | 
			
		||||
        InstructionNotForClaimsError,
 | 
			
		||||
        UnauthorizedError
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Ocelot.Authentication.Middleware;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
using Ocelot.DownstreamUrlCreator.Middleware;
 | 
			
		||||
using Ocelot.HeaderBuilder.Middleware;
 | 
			
		||||
@@ -19,6 +20,8 @@ namespace Ocelot.Middleware
 | 
			
		||||
 | 
			
		||||
            builder.UseAuthenticationMiddleware();
 | 
			
		||||
 | 
			
		||||
            //builder.UseAuthorisationMiddleware();
 | 
			
		||||
 | 
			
		||||
            builder.UseHttpRequestHeadersBuilderMiddleware();
 | 
			
		||||
 | 
			
		||||
            builder.UseDownstreamUrlCreatorMiddleware();
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,92 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.TestHost;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.ScopedData;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Authorization
 | 
			
		||||
{
 | 
			
		||||
    public class AuthorizationMiddlewareTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IScopedRequestDataRepository> _scopedRepository;
 | 
			
		||||
        private readonly Mock<IAuthoriser> _authService;
 | 
			
		||||
        private readonly string _url;
 | 
			
		||||
        private readonly TestServer _server;
 | 
			
		||||
        private readonly HttpClient _client;
 | 
			
		||||
        private HttpResponseMessage _result;
 | 
			
		||||
        private OkResponse<DownstreamRoute> _downstreamRoute;
 | 
			
		||||
 | 
			
		||||
        public AuthorizationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _url = "http://localhost:51879";
 | 
			
		||||
            _scopedRepository = new Mock<IScopedRequestDataRepository>();
 | 
			
		||||
            _authService = new Mock<IAuthoriser>();
 | 
			
		||||
            var builder = new WebHostBuilder()
 | 
			
		||||
              .ConfigureServices(x =>
 | 
			
		||||
              {
 | 
			
		||||
                  x.AddSingleton(_authService.Object);
 | 
			
		||||
                  x.AddSingleton(_scopedRepository.Object);
 | 
			
		||||
              })
 | 
			
		||||
              .UseUrls(_url)
 | 
			
		||||
              .UseKestrel()
 | 
			
		||||
              .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
              .UseIISIntegration()
 | 
			
		||||
              .UseUrls(_url)
 | 
			
		||||
              .Configure(app =>
 | 
			
		||||
              {
 | 
			
		||||
                  app.UseAuthorisationMiddleware();
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
            _server = new TestServer(builder);
 | 
			
		||||
            _client = _server.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void happy_path()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().Build())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheAuthServiceIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAuthServiceIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _authService
 | 
			
		||||
                .Verify(x => x.Authorise(It.IsAny<ClaimsPrincipal>(),
 | 
			
		||||
                It.IsAny<RouteClaimsRequirement>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>()))
 | 
			
		||||
                .Returns(_downstreamRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _client.GetAsync(_url).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _client.Dispose();
 | 
			
		||||
            _server.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user