mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-01 06:15:27 +08:00 
			
		
		
		
	implemented adding claims as query strings to downstream route, removed some of the middleware injection optiosn as i have currently have no use case for them, general refactoring to use the OcelotMiddleware a bit more
This commit is contained in:
		| @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Authentication.Handler.Factory; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.DownstreamRouteFinder; | ||||
| using Ocelot.Errors; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Middleware; | ||||
| @@ -14,7 +13,6 @@ namespace Ocelot.Authentication.Middleware | ||||
|     public class AuthenticationMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
|         private readonly IApplicationBuilder _app; | ||||
|         private readonly IAuthenticationHandlerFactory _authHandlerFactory; | ||||
|  | ||||
| @@ -25,32 +23,23 @@ namespace Ocelot.Authentication.Middleware | ||||
|             : base(requestScopedDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|             _authHandlerFactory = authHandlerFactory; | ||||
|             _app = app; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamRoute = _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); | ||||
|  | ||||
|             if (downstreamRoute.IsError) | ||||
|             if (IsAuthenticatedRoute(DownstreamRoute.ReRoute)) | ||||
|             { | ||||
|                 SetPipelineError(downstreamRoute.Errors); | ||||
|                 return; | ||||
|             } | ||||
|                 var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions); | ||||
|  | ||||
|             if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) | ||||
|             { | ||||
|                 var authenticationNext = _authHandlerFactory.Get(_app, downstreamRoute.Data.ReRoute.AuthenticationOptions); | ||||
|  | ||||
|                 if (!authenticationNext.IsError) | ||||
|                 if (!authenticationHandler.IsError) | ||||
|                 { | ||||
|                     await authenticationNext.Data.Handler.Invoke(context); | ||||
|                     await authenticationHandler.Data.Handler.Invoke(context); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     SetPipelineError(authenticationNext.Errors); | ||||
|                     SetPipelineError(authenticationHandler.Errors); | ||||
|                 } | ||||
|  | ||||
|                 if (context.User.Identity.IsAuthenticated) | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Responses; | ||||
|  | ||||
| namespace Ocelot.Authorisation.Middleware | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using System.Threading.Tasks; | ||||
|     using DownstreamRouteFinder; | ||||
|     using Errors; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|     using Ocelot.Middleware; | ||||
| @@ -12,7 +12,6 @@ namespace Ocelot.Authorisation.Middleware | ||||
|     public class AuthorisationMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
|         private readonly IAuthoriser _authoriser; | ||||
|  | ||||
|         public AuthorisationMiddleware(RequestDelegate next, | ||||
| @@ -21,23 +20,14 @@ namespace Ocelot.Authorisation.Middleware | ||||
|             : base(requestScopedDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|             _authoriser = authoriser; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamRoute = _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); | ||||
|  | ||||
|             if (downstreamRoute.IsError) | ||||
|             if (DownstreamRoute.ReRoute.IsAuthorised) | ||||
|             { | ||||
|                 SetPipelineError(downstreamRoute.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (downstreamRoute.Data.ReRoute.IsAuthorised) | ||||
|             { | ||||
|                 var authorised = _authoriser.Authorise(context.User, downstreamRoute.Data.ReRoute.RouteClaimsRequirement); | ||||
|                 var authorised = _authoriser.Authorise(context.User, DownstreamRoute.ReRoute.RouteClaimsRequirement); | ||||
|  | ||||
|                 if (authorised.IsError) | ||||
|                 { | ||||
| @@ -45,7 +35,7 @@ namespace Ocelot.Authorisation.Middleware | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 if (authorised.Data) | ||||
|                 if (IsAuthorised(authorised)) | ||||
|                 { | ||||
|                     await _next.Invoke(context); | ||||
|                 } | ||||
| @@ -54,7 +44,7 @@ namespace Ocelot.Authorisation.Middleware | ||||
|                     SetPipelineError(new List<Error> | ||||
|                     { | ||||
|                         new UnauthorisedError( | ||||
|                             $"{context.User.Identity.Name} unable to access {downstreamRoute.Data.ReRoute.UpstreamTemplate}") | ||||
|                             $"{context.User.Identity.Name} unable to access {DownstreamRoute.ReRoute.UpstreamTemplate}") | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
| @@ -63,5 +53,10 @@ namespace Ocelot.Authorisation.Middleware | ||||
|                 await _next.Invoke(context); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static bool IsAuthorised(Response<bool> authorised) | ||||
|         { | ||||
|             return authorised.Data; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| namespace Ocelot.ClaimsBuilder | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using System.Linq; | ||||
|     using System.Security.Claims; | ||||
|     using Configuration; | ||||
|     using Infrastructure.Claims.Parser; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|     using Responses; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Security.Claims; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Infrastructure.Claims.Parser; | ||||
| using Ocelot.Responses; | ||||
| 
 | ||||
| namespace Ocelot.Claims | ||||
| { | ||||
|     public class AddClaimsToRequest : IAddClaimsToRequest | ||||
|     { | ||||
|         private readonly IClaimsParser _claimsParser; | ||||
| @@ -37,7 +37,7 @@ | ||||
|                     identity?.RemoveClaim(exists); | ||||
|                 } | ||||
| 
 | ||||
|                 identity?.AddClaim(new Claim(config.ExistingKey, value.Data)); | ||||
|                 identity?.AddClaim(new System.Security.Claims.Claim(config.ExistingKey, value.Data)); | ||||
|             } | ||||
| 
 | ||||
|             return new OkResponse(); | ||||
| @@ -1,10 +1,10 @@ | ||||
| namespace Ocelot.ClaimsBuilder | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using Configuration; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|     using Responses; | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Responses; | ||||
| 
 | ||||
| namespace Ocelot.Claims | ||||
| { | ||||
|     public interface IAddClaimsToRequest | ||||
|     { | ||||
|         Response SetClaimsOnContext(List<ClaimToThing> claimsToThings, | ||||
| @@ -1,18 +1,15 @@ | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Middleware; | ||||
| 
 | ||||
| namespace Ocelot.ClaimsBuilder.Middleware | ||||
| namespace Ocelot.Claims.Middleware | ||||
| { | ||||
|     using System.Linq; | ||||
|     using System.Threading.Tasks; | ||||
|     using DownstreamRouteFinder; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|     using Ocelot.Middleware; | ||||
| 
 | ||||
|     public class ClaimsBuilderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IAddClaimsToRequest _addClaimsToRequest; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
| 
 | ||||
|         public ClaimsBuilderMiddleware(RequestDelegate next,  | ||||
|             IRequestScopedDataRepository requestScopedDataRepository, | ||||
| @@ -21,16 +18,13 @@ namespace Ocelot.ClaimsBuilder.Middleware | ||||
|         { | ||||
|             _next = next; | ||||
|             _addClaimsToRequest = addClaimsToRequest; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamRoute = _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); | ||||
| 
 | ||||
|             if (downstreamRoute.Data.ReRoute.ClaimsToClaims.Any()) | ||||
|             if (DownstreamRoute.ReRoute.ClaimsToClaims.Any()) | ||||
|             { | ||||
|                 var result = _addClaimsToRequest.SetClaimsOnContext(downstreamRoute.Data.ReRoute.ClaimsToClaims, context); | ||||
|                 var result = _addClaimsToRequest.SetClaimsOnContext(DownstreamRoute.ReRoute.ClaimsToClaims, context); | ||||
| 
 | ||||
|                 if (result.IsError) | ||||
|                 { | ||||
| @@ -1,7 +1,7 @@ | ||||
| namespace Ocelot.ClaimsBuilder.Middleware | ||||
| { | ||||
|     using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| 
 | ||||
| namespace Ocelot.Claims.Middleware | ||||
| { | ||||
|     public static class ClaimsBuilderMiddlewareExtensions | ||||
|     { | ||||
|         public static IApplicationBuilder UseClaimsBuilderMiddleware(this IApplicationBuilder builder) | ||||
| @@ -19,6 +19,7 @@ namespace Ocelot.Configuration.Builder | ||||
|         private List<ClaimToThing> _claimToClaims; | ||||
|         private Dictionary<string, string> _routeClaimRequirement; | ||||
|         private bool _isAuthorised; | ||||
|         private List<ClaimToThing> _claimToQueries; | ||||
|  | ||||
|         public ReRouteBuilder() | ||||
|         { | ||||
| @@ -113,9 +114,15 @@ namespace Ocelot.Configuration.Builder | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         public ReRouteBuilder WithClaimsToQueries(List<ClaimToThing> input) | ||||
|         { | ||||
|             _claimToQueries = input; | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         public ReRoute Build() | ||||
|         { | ||||
|             return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement, _isAuthorised); | ||||
|             return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement, _isAuthorised, _claimToQueries); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -100,15 +100,16 @@ namespace Ocelot.Configuration.Creator | ||||
|  | ||||
|                 var claimsToHeaders = GetAddThingsToRequest(reRoute.AddHeadersToRequest); | ||||
|                 var claimsToClaims = GetAddThingsToRequest(reRoute.AddClaimsToRequest); | ||||
|                 var claimsToQueries = GetAddThingsToRequest(reRoute.AddQueriesToRequest); | ||||
|  | ||||
|                 return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, | ||||
|                     reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, | ||||
|                     authOptionsForRoute, claimsToHeaders, claimsToClaims, reRoute.RouteClaimsRequirement, isAuthorised | ||||
|                     authOptionsForRoute, claimsToHeaders, claimsToClaims, reRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries | ||||
|                     ); | ||||
|             } | ||||
|  | ||||
|             return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, | ||||
|                 upstreamTemplate, isAuthenticated, null, new List<ClaimToThing>(), new List<ClaimToThing>(), reRoute.RouteClaimsRequirement, isAuthorised); | ||||
|                 upstreamTemplate, isAuthenticated, null, new List<ClaimToThing>(), new List<ClaimToThing>(), reRoute.RouteClaimsRequirement, isAuthorised, new List<ClaimToThing>()); | ||||
|         } | ||||
|  | ||||
|         private List<ClaimToThing> GetAddThingsToRequest(Dictionary<string,string> thingBeingAdded) | ||||
|   | ||||
| @@ -4,7 +4,7 @@ namespace Ocelot.Configuration | ||||
| { | ||||
|     public class ReRoute | ||||
|     { | ||||
|         public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List<ClaimToThing> configurationHeaderExtractorProperties, List<ClaimToThing> claimsToClaims, Dictionary<string, string> routeClaimsRequirement, bool isAuthorised) | ||||
|         public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List<ClaimToThing> configurationHeaderExtractorProperties, List<ClaimToThing> claimsToClaims, Dictionary<string, string> routeClaimsRequirement, bool isAuthorised, List<ClaimToThing> claimsToQueries) | ||||
|         { | ||||
|             DownstreamTemplate = downstreamTemplate; | ||||
|             UpstreamTemplate = upstreamTemplate; | ||||
| @@ -14,6 +14,8 @@ namespace Ocelot.Configuration | ||||
|             AuthenticationOptions = authenticationOptions; | ||||
|             RouteClaimsRequirement = routeClaimsRequirement; | ||||
|             IsAuthorised = isAuthorised; | ||||
|             ClaimsToQueries = claimsToQueries | ||||
|                 ?? new List<ClaimToThing>(); | ||||
|             ClaimsToClaims = claimsToClaims  | ||||
|                 ?? new List<ClaimToThing>(); | ||||
|             ClaimsToHeaders = configurationHeaderExtractorProperties  | ||||
| @@ -27,6 +29,7 @@ namespace Ocelot.Configuration | ||||
|         public bool IsAuthenticated { get; private set; } | ||||
|         public bool IsAuthorised { get; private set; } | ||||
|         public AuthenticationOptions AuthenticationOptions { get; private set; } | ||||
|         public List<ClaimToThing> ClaimsToQueries { get; private set; } | ||||
|         public List<ClaimToThing> ClaimsToHeaders { get; private set; } | ||||
|         public List<ClaimToThing> ClaimsToClaims { get; private set; } | ||||
|         public Dictionary<string, string> RouteClaimsRequirement { get; private set; } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ namespace Ocelot.Configuration.Yaml | ||||
|             AddHeadersToRequest = new Dictionary<string, string>(); | ||||
|             AddClaimsToRequest = new Dictionary<string, string>(); | ||||
|             RouteClaimsRequirement = new Dictionary<string, string>(); | ||||
|             AddQueriesToRequest = new Dictionary<string, string>(); | ||||
|         } | ||||
|  | ||||
|         public string DownstreamTemplate { get; set; } | ||||
| @@ -18,5 +19,6 @@ namespace Ocelot.Configuration.Yaml | ||||
|         public Dictionary<string, string> AddHeadersToRequest { get; set; } | ||||
|         public Dictionary<string, string> AddClaimsToRequest { get; set; } | ||||
|         public Dictionary<string, string> RouteClaimsRequirement { get; set; } | ||||
|         public Dictionary<string, string> AddQueriesToRequest { get; set; }  | ||||
|     } | ||||
| } | ||||
| @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; | ||||
| using Ocelot.Authentication.Handler.Creator; | ||||
| using Ocelot.Authentication.Handler.Factory; | ||||
| using Ocelot.Authorisation; | ||||
| using Ocelot.Claims; | ||||
| using Ocelot.Configuration.Creator; | ||||
| using Ocelot.Configuration.Parser; | ||||
| using Ocelot.Configuration.Provider; | ||||
| @@ -14,15 +15,15 @@ using Ocelot.Configuration.Yaml; | ||||
| using Ocelot.DownstreamRouteFinder.Finder; | ||||
| using Ocelot.DownstreamRouteFinder.UrlMatcher; | ||||
| using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; | ||||
| using Ocelot.HeaderBuilder; | ||||
| using Ocelot.Headers; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.RequestBuilder.Builder; | ||||
| using Ocelot.QueryStrings; | ||||
| using Ocelot.Request.Builder; | ||||
| using Ocelot.Requester; | ||||
| using Ocelot.Responder; | ||||
|  | ||||
| namespace Ocelot.DependencyInjection | ||||
| { | ||||
|     using ClaimsBuilder; | ||||
|     using Infrastructure.Claims.Parser; | ||||
|  | ||||
|     public static class ServiceCollectionExtensions | ||||
| @@ -52,6 +53,7 @@ namespace Ocelot.DependencyInjection | ||||
|             services.AddSingleton<IAuthoriser, ClaimsAuthoriser>(); | ||||
|             services.AddSingleton<IAddClaimsToRequest, AddClaimsToRequest>(); | ||||
|             services.AddSingleton<IAddHeadersToRequest, AddHeadersToRequest>(); | ||||
|             services.AddSingleton<IAddQueriesToRequest, AddQueriesToRequest>(); | ||||
|             services.AddSingleton<IClaimsParser, ClaimsParser>(); | ||||
|             services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>(); | ||||
|             services.AddSingleton<IUrlPathPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>(); | ||||
|   | ||||
| @@ -34,7 +34,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             _requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute.Data); | ||||
|             SetDownstreamRouteForThisRequest(downstreamRoute.Data); | ||||
|  | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|   | ||||
| @@ -11,7 +11,6 @@ namespace Ocelot.DownstreamUrlCreator.Middleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IDownstreamUrlPathPlaceholderReplacer _urlReplacer; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
|  | ||||
|         public DownstreamUrlCreatorMiddleware(RequestDelegate next,  | ||||
|             IDownstreamUrlPathPlaceholderReplacer urlReplacer, | ||||
| @@ -20,20 +19,11 @@ namespace Ocelot.DownstreamUrlCreator.Middleware | ||||
|         { | ||||
|             _next = next; | ||||
|             _urlReplacer = urlReplacer; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamRoute = _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); | ||||
|  | ||||
|             if (downstreamRoute.IsError) | ||||
|             { | ||||
|                 SetPipelineError(downstreamRoute.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var downstreamUrl = _urlReplacer.Replace(downstreamRoute.Data.ReRoute.DownstreamTemplate, downstreamRoute.Data.TemplatePlaceholderNameAndValues); | ||||
|             var downstreamUrl = _urlReplacer.Replace(DownstreamRoute.ReRoute.DownstreamTemplate, DownstreamRoute.TemplatePlaceholderNameAndValues); | ||||
|  | ||||
|             if (downstreamUrl.IsError) | ||||
|             { | ||||
| @@ -41,8 +31,8 @@ namespace Ocelot.DownstreamUrlCreator.Middleware | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             _requestScopedDataRepository.Add("DownstreamUrl", downstreamUrl.Data.Value); | ||||
|                  | ||||
|             SetDownstreamUrlForThisRequest(downstreamUrl.Data.Value); | ||||
|  | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -3,12 +3,11 @@ using System.Linq; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.Primitives; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Infrastructure.Claims.Parser; | ||||
| using Ocelot.Responses; | ||||
| 
 | ||||
| namespace Ocelot.HeaderBuilder | ||||
| namespace Ocelot.Headers | ||||
| { | ||||
|     using Infrastructure.Claims.Parser; | ||||
| 
 | ||||
|     public class AddHeadersToRequest : IAddHeadersToRequest | ||||
|     { | ||||
|         private readonly IClaimsParser _claimsParser; | ||||
| @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Responses; | ||||
| 
 | ||||
| namespace Ocelot.HeaderBuilder | ||||
| namespace Ocelot.Headers | ||||
| { | ||||
|     public interface IAddHeadersToRequest | ||||
|     { | ||||
| @@ -1,17 +1,15 @@ | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.DownstreamRouteFinder; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Middleware; | ||||
| 
 | ||||
| namespace Ocelot.HeaderBuilder.Middleware | ||||
| namespace Ocelot.Headers.Middleware | ||||
| { | ||||
|     public class HttpRequestHeadersBuilderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IAddHeadersToRequest _addHeadersToRequest; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
| 
 | ||||
|         public HttpRequestHeadersBuilderMiddleware(RequestDelegate next,  | ||||
|             IRequestScopedDataRepository requestScopedDataRepository, | ||||
| @@ -20,16 +18,13 @@ namespace Ocelot.HeaderBuilder.Middleware | ||||
|         { | ||||
|             _next = next; | ||||
|             _addHeadersToRequest = addHeadersToRequest; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamRoute = _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); | ||||
| 
 | ||||
|             if (downstreamRoute.Data.ReRoute.ClaimsToHeaders.Any()) | ||||
|             if (DownstreamRoute.ReRoute.ClaimsToHeaders.Any()) | ||||
|             { | ||||
|                 _addHeadersToRequest.SetHeadersOnContext(downstreamRoute.Data.ReRoute.ClaimsToHeaders, context); | ||||
|                 _addHeadersToRequest.SetHeadersOnContext(DownstreamRoute.ReRoute.ClaimsToHeaders, context); | ||||
|             } | ||||
|              | ||||
|             await _next.Invoke(context); | ||||
| @@ -1,6 +1,6 @@ | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| 
 | ||||
| namespace Ocelot.HeaderBuilder.Middleware | ||||
| namespace Ocelot.Headers.Middleware | ||||
| { | ||||
|     public static class HttpRequestHeadersBuilderMiddlewareExtensions | ||||
|     { | ||||
| @@ -1,4 +1,5 @@ | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.DownstreamRouteFinder; | ||||
| using Ocelot.Errors; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
|  | ||||
| @@ -30,5 +31,47 @@ namespace Ocelot.Middleware | ||||
|             var response = _requestScopedDataRepository.Get<List<Error>>("OcelotMiddlewareErrors"); | ||||
|             return response.Data; | ||||
|         } | ||||
|  | ||||
|         public DownstreamRoute DownstreamRoute | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 var downstreamRoute = _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); | ||||
|                 return downstreamRoute.Data; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public string DownstreamUrl | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 var downstreamUrl = _requestScopedDataRepository.Get<string>("DownstreamUrl"); | ||||
|                 return downstreamUrl.Data; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public Request.Request Request | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 var request = _requestScopedDataRepository.Get<Request.Request>("Request"); | ||||
|                 return request.Data; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute) | ||||
|         { | ||||
|             _requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute); | ||||
|         } | ||||
|  | ||||
|         public void SetDownstreamUrlForThisRequest(string downstreamUrl) | ||||
|         { | ||||
|             _requestScopedDataRepository.Add("DownstreamUrl", downstreamUrl); | ||||
|         } | ||||
|  | ||||
|         public void SetUpstreamRequestForThisRequest(Request.Request request) | ||||
|         { | ||||
|             _requestScopedDataRepository.Add("Request", request); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,23 +5,10 @@ | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|  | ||||
|     public class OcelotMiddlewareConfiguration | ||||
|     { | ||||
|         public Func<HttpContext, Func<Task>, Task> PreHttpResponderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostHttpResponderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreDownstreamRouteFinderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostDownstreamRouteFinderMiddleware { get; set; } | ||||
|     {  | ||||
|         public Func<HttpContext, Func<Task>, Task> PreAuthenticationMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostAuthenticationMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreClaimsBuilderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostClaimsBuilderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> AuthenticationMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreAuthorisationMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostAuthorisationMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreHttpRequestHeadersBuilderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostHttpRequestHeadersBuilderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreDownstreamUrlCreatorMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostDownstreamUrlCreatorMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreHttpRequestBuilderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PostHttpRequestBuilderMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> PreHttpRequesterMiddleware { get; set; } | ||||
|         public Func<HttpContext, Func<Task>, Task> AuthorisationMiddleware { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +1,11 @@ | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Ocelot.Authentication.Middleware; | ||||
| using Ocelot.Claims.Middleware; | ||||
| using Ocelot.DownstreamRouteFinder.Middleware; | ||||
| using Ocelot.DownstreamUrlCreator.Middleware; | ||||
| using Ocelot.HeaderBuilder.Middleware; | ||||
| using Ocelot.RequestBuilder.Middleware; | ||||
| using Ocelot.Headers.Middleware; | ||||
| using Ocelot.QueryStrings.Middleware; | ||||
| using Ocelot.Request.Middleware; | ||||
| using Ocelot.Requester.Middleware; | ||||
| using Ocelot.Responder.Middleware; | ||||
|  | ||||
| @@ -12,12 +14,17 @@ namespace Ocelot.Middleware | ||||
|     using System; | ||||
|     using System.Threading.Tasks; | ||||
|     using Authorisation.Middleware; | ||||
|     using ClaimsBuilder.Middleware; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|  | ||||
|     public static class OcelotMiddlewareExtensions | ||||
|     { | ||||
|         public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder) | ||||
|         { | ||||
|             builder.UseOcelot(new OcelotMiddlewareConfiguration()); | ||||
|             return builder; | ||||
|         } | ||||
|  | ||||
|         public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration) | ||||
|         { | ||||
|             // This is registered to catch any global exceptions that are not handled | ||||
|             builder.UseExceptionHandlerMiddleware(); | ||||
| @@ -28,18 +35,46 @@ namespace Ocelot.Middleware | ||||
|             // Then we get the downstream route information | ||||
|             builder.UseDownstreamRouteFinderMiddleware(); | ||||
|  | ||||
|             // Now we know where the client is going to go we can authenticate them | ||||
|             builder.UseAuthenticationMiddleware(); | ||||
|             // Allow pre authentication logic. The idea being people might want to run something custom before what is built in. | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreAuthenticationMiddleware); | ||||
|  | ||||
|             // Now we know where the client is going to go we can authenticate them. | ||||
|             // We allow the ocelot middleware to be overriden by whatever the | ||||
|             // user wants | ||||
|             if (middlewareConfiguration.AuthenticationMiddleware == null) | ||||
|             { | ||||
|                 builder.UseAuthenticationMiddleware(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 builder.Use(middlewareConfiguration.AuthenticationMiddleware); | ||||
|             } | ||||
|  | ||||
|             // The next thing we do is look at any claims transforms in case this is important for authorisation | ||||
|             builder.UseClaimsBuilderMiddleware(); | ||||
|  | ||||
|             // Now we have authenticated and done any claims transformation we can authorise the request | ||||
|             builder.UseAuthorisationMiddleware(); | ||||
|             // Allow pre authorisation logic. The idea being people might want to run something custom before what is built in. | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreAuthorisationMiddleware); | ||||
|  | ||||
|             // Now we have authenticated and done any claims transformation we  | ||||
|             // can authorise the request | ||||
|             // We allow the ocelot middleware to be overriden by whatever the | ||||
|             // user wants | ||||
|             if (middlewareConfiguration.AuthorisationMiddleware == null) | ||||
|             { | ||||
|                 builder.UseAuthorisationMiddleware(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 builder.Use(middlewareConfiguration.AuthorisationMiddleware); | ||||
|             } | ||||
|  | ||||
|             // Now we can run any header transformation logic | ||||
|             builder.UseHttpRequestHeadersBuilderMiddleware(); | ||||
|  | ||||
|             // Now we can run any query string transformation logic | ||||
|             builder.UseQueryStringBuilderMiddleware(); | ||||
|  | ||||
|             // This takes the downstream route we retrieved earlier and replaces any placeholders with the variables that should be used | ||||
|             builder.UseDownstreamUrlCreatorMiddleware(); | ||||
|  | ||||
| @@ -52,63 +87,6 @@ namespace Ocelot.Middleware | ||||
|             return builder; | ||||
|         } | ||||
|  | ||||
|         public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration) | ||||
|         { | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreHttpResponderMiddleware); | ||||
|  | ||||
|             builder.UseHttpErrorResponderMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostHttpResponderMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreDownstreamRouteFinderMiddleware); | ||||
|  | ||||
|             builder.UseDownstreamRouteFinderMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostDownstreamRouteFinderMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreAuthenticationMiddleware); | ||||
|  | ||||
|             builder.UseAuthenticationMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostAuthenticationMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreClaimsBuilderMiddleware); | ||||
|  | ||||
|             builder.UseClaimsBuilderMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostClaimsBuilderMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreAuthorisationMiddleware); | ||||
|  | ||||
|             builder.UseAuthorisationMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostAuthorisationMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreHttpRequestHeadersBuilderMiddleware); | ||||
|  | ||||
|             builder.UseHttpRequestHeadersBuilderMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostHttpRequestHeadersBuilderMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreDownstreamUrlCreatorMiddleware); | ||||
|  | ||||
|             builder.UseDownstreamUrlCreatorMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostDownstreamUrlCreatorMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreHttpRequestBuilderMiddleware); | ||||
|  | ||||
|             builder.UseHttpRequestBuilderMiddleware(); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PostHttpRequestBuilderMiddleware); | ||||
|  | ||||
|             builder.UseIfNotNull(middlewareConfiguration.PreHttpRequesterMiddleware); | ||||
|  | ||||
|             builder.UseHttpRequesterMiddleware(); | ||||
|  | ||||
|             return builder; | ||||
|         } | ||||
|  | ||||
|         private static void UseIfNotNull(this IApplicationBuilder builder, Func<HttpContext, Func<Task>, Task> middleware) | ||||
|         { | ||||
|             if (middleware != null) | ||||
|   | ||||
							
								
								
									
										62
									
								
								src/Ocelot/QueryStrings/AddQueriesToRequest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/Ocelot/QueryStrings/AddQueriesToRequest.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Infrastructure.Claims.Parser; | ||||
| using Ocelot.Responses; | ||||
|  | ||||
| namespace Ocelot.QueryStrings | ||||
| { | ||||
|     public class AddQueriesToRequest : IAddQueriesToRequest | ||||
|     { | ||||
|         private readonly IClaimsParser _claimsParser; | ||||
|  | ||||
|         public AddQueriesToRequest(IClaimsParser claimsParser) | ||||
|         { | ||||
|             _claimsParser = claimsParser; | ||||
|         } | ||||
|  | ||||
|         public Response SetQueriesOnContext(List<ClaimToThing> claimsToThings, HttpContext context) | ||||
|         { | ||||
|             var queryDictionary = ConvertQueryStringToDictionary(context); | ||||
|  | ||||
|             foreach (var config in claimsToThings) | ||||
|             { | ||||
|                 var value = _claimsParser.GetValue(context.User.Claims, config.NewKey, config.Delimiter, config.Index); | ||||
|  | ||||
|                 if (value.IsError) | ||||
|                 { | ||||
|                     return new ErrorResponse(value.Errors); | ||||
|                 } | ||||
|  | ||||
|                 var exists = queryDictionary.FirstOrDefault(x => x.Key == config.ExistingKey); | ||||
|  | ||||
|                 if (!string.IsNullOrEmpty(exists.Key)) | ||||
|                 { | ||||
|                     queryDictionary[exists.Key] = value.Data; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     queryDictionary.Add(config.ExistingKey, value.Data); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             context.Request.QueryString = ConvertDictionaryToQueryString(queryDictionary); | ||||
|  | ||||
|             return new OkResponse(); | ||||
|         } | ||||
|  | ||||
|         private Dictionary<string, string> ConvertQueryStringToDictionary(HttpContext context) | ||||
|         { | ||||
|             return Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(context.Request.QueryString.Value) | ||||
|                 .ToDictionary(q => q.Key, q => q.Value.FirstOrDefault() ?? string.Empty); | ||||
|         } | ||||
|  | ||||
|         private Microsoft.AspNetCore.Http.QueryString ConvertDictionaryToQueryString(Dictionary<string, string> queryDictionary) | ||||
|         { | ||||
|             var newQueryString = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString("", queryDictionary); | ||||
|  | ||||
|             return new Microsoft.AspNetCore.Http.QueryString(newQueryString); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/Ocelot/QueryStrings/IAddQueriesToRequest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/Ocelot/QueryStrings/IAddQueriesToRequest.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Responses; | ||||
|  | ||||
| namespace Ocelot.QueryStrings | ||||
| { | ||||
|     public interface IAddQueriesToRequest | ||||
|     { | ||||
|         Response SetQueriesOnContext(List<ClaimToThing> claimsToThings, | ||||
|             HttpContext context); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Middleware; | ||||
|  | ||||
| namespace Ocelot.QueryStrings.Middleware | ||||
| { | ||||
|     public class QueryStringBuilderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IAddQueriesToRequest _addQueriesToRequest; | ||||
|  | ||||
|         public QueryStringBuilderMiddleware(RequestDelegate next,  | ||||
|             IRequestScopedDataRepository requestScopedDataRepository, | ||||
|             IAddQueriesToRequest addQueriesToRequest)  | ||||
|             : base(requestScopedDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _addQueriesToRequest = addQueriesToRequest; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             if (DownstreamRoute.ReRoute.ClaimsToQueries.Any()) | ||||
|             { | ||||
|                 _addQueriesToRequest.SetQueriesOnContext(DownstreamRoute.ReRoute.ClaimsToQueries, context); | ||||
|             } | ||||
|              | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using Microsoft.AspNetCore.Builder; | ||||
|  | ||||
| namespace Ocelot.QueryStrings.Middleware | ||||
| { | ||||
|     public static class QueryStringBuilderMiddlewareExtensions | ||||
|     { | ||||
|         public static IApplicationBuilder UseQueryStringBuilderMiddleware(this IApplicationBuilder builder) | ||||
|         { | ||||
|             return builder.UseMiddleware<QueryStringBuilderMiddleware>(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,23 +2,21 @@ | ||||
| using System.IO; | ||||
| using System.Net; | ||||
| using System.Net.Http; | ||||
| using System.Net.Http.Headers; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Responses; | ||||
| 
 | ||||
| namespace Ocelot.RequestBuilder.Builder | ||||
| namespace Ocelot.Request.Builder | ||||
| { | ||||
|     public class HttpRequestBuilder : IRequestBuilder | ||||
|     { | ||||
|         public async Task<Response<Request>> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, | ||||
|             IRequestCookieCollection cookies, QueryString queryString, string contentType) | ||||
|             IRequestCookieCollection cookies, Microsoft.AspNetCore.Http.QueryString queryString, string contentType) | ||||
|         { | ||||
|             var method = new HttpMethod(httpMethod); | ||||
| 
 | ||||
|             var uri = new Uri(string.Format("{0}{1}", downstreamUrl, queryString.ToUriComponent())); | ||||
| 
 | ||||
| 
 | ||||
|             var httpRequestMessage = new HttpRequestMessage(method, uri); | ||||
| 
 | ||||
|             if (content != null) | ||||
| @@ -3,7 +3,7 @@ using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Responses; | ||||
| 
 | ||||
| namespace Ocelot.RequestBuilder.Builder | ||||
| namespace Ocelot.Request.Builder | ||||
| { | ||||
|     public interface IRequestBuilder | ||||
|     { | ||||
| @@ -12,7 +12,7 @@ namespace Ocelot.RequestBuilder.Builder | ||||
|             Stream content, | ||||
|             IHeaderDictionary headers, | ||||
|             IRequestCookieCollection cookies, | ||||
|             QueryString queryString, | ||||
|             Microsoft.AspNetCore.Http.QueryString queryString, | ||||
|             string contentType); | ||||
|     } | ||||
| } | ||||
| @@ -2,14 +2,13 @@ using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Middleware; | ||||
| using Ocelot.RequestBuilder.Builder; | ||||
| using Ocelot.Request.Builder; | ||||
| 
 | ||||
| namespace Ocelot.RequestBuilder.Middleware | ||||
| namespace Ocelot.Request.Middleware | ||||
| { | ||||
|     public class HttpRequestBuilderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
|         private readonly IRequestBuilder _requestBuilder; | ||||
| 
 | ||||
|         public HttpRequestBuilderMiddleware(RequestDelegate next,  | ||||
| @@ -18,22 +17,13 @@ namespace Ocelot.RequestBuilder.Middleware | ||||
|             :base(requestScopedDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|             _requestBuilder = requestBuilder; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamUrl = _requestScopedDataRepository.Get<string>("DownstreamUrl"); | ||||
| 
 | ||||
|             if (downstreamUrl.IsError) | ||||
|             { | ||||
|                 SetPipelineError(downstreamUrl.Errors); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             var request = await _requestBuilder | ||||
|               .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, | ||||
|               .Build(context.Request.Method, DownstreamUrl, context.Request.Body, | ||||
|               context.Request.Headers, context.Request.Cookies, context.Request.QueryString, context.Request.ContentType); | ||||
| 
 | ||||
|             if (request.IsError) | ||||
| @@ -42,7 +32,7 @@ namespace Ocelot.RequestBuilder.Middleware | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             _requestScopedDataRepository.Add("Request", request.Data); | ||||
|             SetUpstreamRequestForThisRequest(request.Data); | ||||
| 
 | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
| @@ -1,6 +1,6 @@ | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| 
 | ||||
| namespace Ocelot.RequestBuilder.Middleware | ||||
| namespace Ocelot.Request.Middleware | ||||
| { | ||||
|     public static class HttpRequestBuilderMiddlewareExtensions | ||||
|     { | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Net; | ||||
| using System.Net.Http; | ||||
| 
 | ||||
| namespace Ocelot.RequestBuilder | ||||
| namespace Ocelot.Request | ||||
| { | ||||
|     public class Request | ||||
|     { | ||||
| @@ -3,14 +3,13 @@ using System.Collections.Generic; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Ocelot.Errors; | ||||
| using Ocelot.RequestBuilder; | ||||
| using Ocelot.Responses; | ||||
|  | ||||
| namespace Ocelot.Requester | ||||
| { | ||||
|     public class HttpClientHttpRequester : IHttpRequester | ||||
|     { | ||||
|         public async Task<Response<HttpResponseMessage>> GetResponse(Request request) | ||||
|         public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request) | ||||
|         { | ||||
|             using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer }) | ||||
|             using (var httpClient = new HttpClient(handler)) | ||||
|   | ||||
| @@ -1,12 +1,11 @@ | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Ocelot.RequestBuilder; | ||||
| using Ocelot.Responses; | ||||
|  | ||||
| namespace Ocelot.Requester | ||||
| { | ||||
|     public interface IHttpRequester | ||||
|     { | ||||
|         Task<Response<HttpResponseMessage>> GetResponse(Request request); | ||||
|         Task<Response<HttpResponseMessage>> GetResponse(Request.Request request); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,6 @@ using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Middleware; | ||||
| using Ocelot.RequestBuilder; | ||||
| using Ocelot.Responder; | ||||
|  | ||||
| namespace Ocelot.Requester.Middleware | ||||
| @@ -11,7 +10,6 @@ namespace Ocelot.Requester.Middleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IHttpRequester _requester; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
|         private readonly IHttpResponder _responder; | ||||
|  | ||||
|         public HttpRequesterMiddleware(RequestDelegate next,  | ||||
| @@ -22,21 +20,13 @@ namespace Ocelot.Requester.Middleware | ||||
|         { | ||||
|             _next = next; | ||||
|             _requester = requester; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|             _responder = responder; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var request = _requestScopedDataRepository.Get<Request>("Request"); | ||||
|  | ||||
|             if (request.IsError) | ||||
|             { | ||||
|                 SetPipelineError(request.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var response = await _requester.GetResponse(request.Data); | ||||
|             var response = await _requester.GetResponse(Request); | ||||
|  | ||||
|             if (response.IsError) | ||||
|             { | ||||
|   | ||||
| @@ -10,7 +10,6 @@ namespace Ocelot.Responder.Middleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IHttpResponder _responder; | ||||
|         private readonly IRequestScopedDataRepository _requestScopedDataRepository; | ||||
|         private readonly IErrorsToHttpStatusCodeMapper _codeMapper; | ||||
|  | ||||
|         public HttpErrorResponderMiddleware(RequestDelegate next,  | ||||
| @@ -21,7 +20,6 @@ namespace Ocelot.Responder.Middleware | ||||
|         { | ||||
|             _next = next; | ||||
|             _responder = responder; | ||||
|             _requestScopedDataRepository = requestScopedDataRepository; | ||||
|             _codeMapper = codeMapper; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,194 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Net; | ||||
| using System.Security.Claims; | ||||
| using IdentityServer4.Models; | ||||
| using IdentityServer4.Services.InMemory; | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Primitives; | ||||
| using Ocelot.Configuration.Yaml; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
|  | ||||
| namespace Ocelot.AcceptanceTests | ||||
| { | ||||
|     public class ClaimsToQueryStringForwardingTests : IDisposable | ||||
|     { | ||||
|         private IWebHost _servicebuilder; | ||||
|         private IWebHost _identityServerBuilder; | ||||
|         private readonly Steps _steps; | ||||
|  | ||||
|         public ClaimsToQueryStringForwardingTests() | ||||
|         { | ||||
|             _steps = new Steps(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_return_response_200_and_foward_claim_as_query_string() | ||||
|         { | ||||
|             var user = new InMemoryUser | ||||
|             { | ||||
|                 Username = "test", | ||||
|                 Password = "test", | ||||
|                 Enabled = true, | ||||
|                 Subject = "registered|1231231", | ||||
|                 Claims = new List<Claim> | ||||
|                 { | ||||
|                     new Claim("CustomerId", "123"), | ||||
|                     new Claim("LocationId", "1") | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             var yamlConfiguration = new YamlConfiguration | ||||
|             { | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                     { | ||||
|                         new YamlReRoute | ||||
|                         { | ||||
|                             DownstreamTemplate = "http://localhost:57876/", | ||||
|                             UpstreamTemplate = "/", | ||||
|                             UpstreamHttpMethod = "Get", | ||||
|                             AuthenticationOptions = new YamlAuthenticationOptions | ||||
|                             { | ||||
|                                 AdditionalScopes = new List<string> | ||||
|                                 { | ||||
|                                     "openid", "offline_access" | ||||
|                                 }, | ||||
|                                 Provider = "IdentityServer", | ||||
|                                 ProviderRootUrl = "http://localhost:57888", | ||||
|                                 RequireHttps = false, | ||||
|                                 ScopeName = "api", | ||||
|                                 ScopeSecret = "secret", | ||||
|                             }, | ||||
|                             AddQueriesToRequest = | ||||
|                             { | ||||
|                                 {"CustomerId", "Claims[CustomerId] > value"}, | ||||
|                                 {"LocationId", "Claims[LocationId] > value"}, | ||||
|                                 {"UserType", "Claims[sub] > value[0] > |"}, | ||||
|                                 {"UserId", "Claims[sub] > value[1] > |"} | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|             }; | ||||
|  | ||||
|             this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:57888", "api", AccessTokenType.Jwt, user)) | ||||
|                 .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) | ||||
|                 .And(x => _steps.GivenIHaveAToken("http://localhost:57888")) | ||||
|                 .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) | ||||
|                 .And(x => _steps.GivenOcelotIsRunning()) | ||||
|                 .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) | ||||
|                 .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) | ||||
|                 .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) | ||||
|                 .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void GivenThereIsAServiceRunningOn(string url, int statusCode) | ||||
|         { | ||||
|             _servicebuilder = new WebHostBuilder() | ||||
|                 .UseUrls(url) | ||||
|                 .UseKestrel() | ||||
|                 .UseContentRoot(Directory.GetCurrentDirectory()) | ||||
|                 .UseIISIntegration() | ||||
|                 .UseUrls(url) | ||||
|                 .Configure(app => | ||||
|                 { | ||||
|                     app.Run(async context => | ||||
|                     { | ||||
|                         StringValues customerId; | ||||
|                         context.Request.Query.TryGetValue("CustomerId", out customerId); | ||||
|  | ||||
|                         StringValues locationId; | ||||
|                         context.Request.Query.TryGetValue("LocationId", out locationId); | ||||
|  | ||||
|                         StringValues userType; | ||||
|                         context.Request.Query.TryGetValue("UserType", out userType); | ||||
|  | ||||
|                         StringValues userId; | ||||
|                         context.Request.Query.TryGetValue("UserId", out userId); | ||||
|  | ||||
|                         var responseBody = $"CustomerId: {customerId} LocationId: {locationId} UserType: {userType} UserId: {userId}"; | ||||
|                         context.Response.StatusCode = statusCode; | ||||
|                         await context.Response.WriteAsync(responseBody); | ||||
|                     }); | ||||
|                 }) | ||||
|                 .Build(); | ||||
|  | ||||
|             _servicebuilder.Start(); | ||||
|         } | ||||
|  | ||||
|         private void GivenThereIsAnIdentityServerOn(string url, string scopeName, AccessTokenType tokenType, InMemoryUser user) | ||||
|         { | ||||
|             _identityServerBuilder = new WebHostBuilder() | ||||
|                 .UseUrls(url) | ||||
|                 .UseKestrel() | ||||
|                 .UseContentRoot(Directory.GetCurrentDirectory()) | ||||
|                 .UseIISIntegration() | ||||
|                 .UseUrls(url) | ||||
|                 .ConfigureServices(services => | ||||
|                 { | ||||
|                     services.AddLogging(); | ||||
|                     services.AddDeveloperIdentityServer() | ||||
|                         .AddInMemoryScopes(new List<Scope> | ||||
|                         { | ||||
|                             new Scope | ||||
|                             { | ||||
|                                 Name = scopeName, | ||||
|                                 Description = "My API", | ||||
|                                 Enabled = true, | ||||
|                                 AllowUnrestrictedIntrospection = true, | ||||
|                                 ScopeSecrets = new List<Secret>() | ||||
|                                 { | ||||
|                                     new Secret | ||||
|                                     { | ||||
|                                         Value = "secret".Sha256() | ||||
|                                     } | ||||
|                                 }, | ||||
|                                 IncludeAllClaimsForUser = true | ||||
|                             }, | ||||
|  | ||||
|                             StandardScopes.OpenId, | ||||
|                             StandardScopes.OfflineAccess | ||||
|                         }) | ||||
|                         .AddInMemoryClients(new List<Client> | ||||
|                         { | ||||
|                             new Client | ||||
|                             { | ||||
|                                 ClientId = "client", | ||||
|                                 AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, | ||||
|                                 ClientSecrets = new List<Secret> {new Secret("secret".Sha256())}, | ||||
|                                 AllowedScopes = new List<string> { scopeName, "openid", "offline_access" }, | ||||
|                                 AccessTokenType = tokenType, | ||||
|                                 Enabled = true, | ||||
|                                 RequireClientSecret = false | ||||
|                             } | ||||
|                         }) | ||||
|                         .AddInMemoryUsers(new List<InMemoryUser> | ||||
|                         { | ||||
|                             user | ||||
|                         }); | ||||
|                 }) | ||||
|                 .Configure(app => | ||||
|                 { | ||||
|                     app.UseIdentityServer(); | ||||
|                 }) | ||||
|                 .Build(); | ||||
|  | ||||
|             _identityServerBuilder.Start(); | ||||
|  | ||||
|             _steps.VerifyIdentiryServerStarted(url); | ||||
|         } | ||||
|  | ||||
|         public void Dispose() | ||||
|         { | ||||
|             _servicebuilder?.Dispose(); | ||||
|             _steps.Dispose(); | ||||
|             _identityServerBuilder?.Dispose(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -29,11 +29,11 @@ namespace Ocelot.AcceptanceTests | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void response_should_come_from_pre_http_responder_middleware() | ||||
|         public void response_should_come_from_pre_authorisation_middleware() | ||||
|         { | ||||
|             var configuration = new OcelotMiddlewareConfiguration | ||||
|             { | ||||
|                 PreHttpResponderMiddleware = async (ctx, next) => | ||||
|                 PreAuthorisationMiddleware = async (ctx, next) => | ||||
|                 { | ||||
|                     await ctx.Response.WriteAsync("PreHttpResponderMiddleware"); | ||||
|                 } | ||||
| @@ -62,11 +62,11 @@ namespace Ocelot.AcceptanceTests | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void response_should_come_from_pre_http_requester_middleware() | ||||
|         public void response_should_come_from_pre_http_authentication_middleware() | ||||
|         { | ||||
|             var configuration = new OcelotMiddlewareConfiguration | ||||
|             { | ||||
|                 PreHttpRequesterMiddleware = async (ctx, next) => | ||||
|                 PreAuthenticationMiddleware = async (ctx, next) => | ||||
|                 { | ||||
|                     await ctx.Response.WriteAsync("PreHttpRequesterMiddleware"); | ||||
|                 } | ||||
|   | ||||
| @@ -5,3 +5,4 @@ ReRoutes: | ||||
|   AddHeadersToRequest: {} | ||||
|   AddClaimsToRequest: {} | ||||
|   RouteClaimsRequirement: {} | ||||
|   AddQueriesToRequest: {} | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| ReRoutes: | ||||
| # the url we are forwarding the request to | ||||
| # The url we are forwarding the request to | ||||
| - DownstreamTemplate: http://localhost:52876/ | ||||
| # the path we are listening on for this re route | ||||
| # The path we are listening on for this re route | ||||
|   UpstreamTemplate: /identityserverexample | ||||
| # the method we are listening for on this re route | ||||
| # The method we are listening for on this re route | ||||
|   UpstreamHttpMethod: Get | ||||
| # only support identity server at the moment | ||||
| # Only support identity server at the moment | ||||
|   AuthenticationOptions: | ||||
|     Provider: IdentityServer | ||||
|     ProviderRootUrl: http://localhost:52888 | ||||
| @@ -13,14 +13,44 @@ ReRoutes: | ||||
|     AdditionalScopes: | ||||
|     - openid | ||||
|     - offline_access | ||||
| #require if using reference tokens | ||||
| # Required if using reference tokens | ||||
|     ScopeSecret: secret | ||||
| # WARNING - will overwrite any headers already in the request with these values | ||||
| # WARNING - will overwrite any headers already in the request with these values. | ||||
| # Ocelot will look in the user claims for the key in [] then return the value and save | ||||
| # it as a header with the given key before the colon (:). The index selection on value  | ||||
| # means that Ocelot will use the delimiter specified after the next > to split the  | ||||
| # claim value and return the index specified. | ||||
|   AddHeadersToRequest: | ||||
|     CustomerId: Claims[CustomerId] > value | ||||
|     LocationId: Claims[LocationId] > value | ||||
|     UserType: Claims[sub] > value[0] > | | ||||
|     UserId: Claims[sub] > value[1] > | | ||||
| # WARNING - will overwrite any claims already in the request with these values. | ||||
| # Ocelot will look in the user claims for the key in [] then return the value and save | ||||
| # it as a claim with the given key before the colon (:). The index selection on value  | ||||
| # means that Ocelot will use the delimiter specified after the next > to split the  | ||||
| # claim value and return the index specified. | ||||
| AddClaimsToRequest: | ||||
|     CustomerId: Claims[CustomerId] > value | ||||
|     LocationId: Claims[LocationId] > value | ||||
|     UserType: Claims[sub] > value[0] > | | ||||
|     UserId: Claims[sub] > value[1] > | | ||||
| # WARNING - will overwrite any query string entries already in the request with these values. | ||||
| # Ocelot will look in the user claims for the key in [] then return the value and save | ||||
| # it as a query string with the given key before the colon (:). The index selection on value  | ||||
| # means that Ocelot will use the delimiter specified after the next > to split the  | ||||
| # claim value and return the index specified. | ||||
| AddQueriesToRequest: | ||||
|     CustomerId: Claims[CustomerId] > value | ||||
|     LocationId: Claims[LocationId] > value | ||||
|     UserType: Claims[sub] > value[0] > | | ||||
|     UserId: Claims[sub] > value[1] > | | ||||
| # This specifies any claims that are required for the user to access this re route. | ||||
| # In this example the user must have the claim type UserType and  | ||||
| # the value must be registered | ||||
| RouteClaimsRequirement: | ||||
|     UserType: registered | ||||
| # The next re route... | ||||
| - DownstreamTemplate: http://jsonplaceholder.typicode.com/posts | ||||
|   UpstreamTemplate: /posts | ||||
|   UpstreamHttpMethod: Get | ||||
|   | ||||
| @@ -1,19 +1,18 @@ | ||||
| namespace Ocelot.UnitTests.ClaimsBuilder | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using System.Linq; | ||||
|     using System.Security.Claims; | ||||
|     using Errors; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|     using Moq; | ||||
|     using Ocelot.ClaimsBuilder; | ||||
|     using Ocelot.Configuration; | ||||
|     using Ocelot.Infrastructure.Claims.Parser; | ||||
|     using Responses; | ||||
|     using Shouldly; | ||||
|     using TestStack.BDDfy; | ||||
|     using Xunit; | ||||
| using System.Collections.Generic; | ||||
| using System.Security.Claims; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Moq; | ||||
| using Ocelot.Claims; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Errors; | ||||
| using Ocelot.Infrastructure.Claims.Parser; | ||||
| using Ocelot.Responses; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace Ocelot.UnitTests.Claims | ||||
| { | ||||
|     public class AddClaimsToRequestTests | ||||
|     { | ||||
|         private readonly AddClaimsToRequest _addClaimsToRequest; | ||||
| @@ -1,26 +1,25 @@ | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Net.Http; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.AspNetCore.TestHost; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Moq; | ||||
| using Ocelot.Claims; | ||||
| using Ocelot.Claims.Middleware; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Configuration.Builder; | ||||
| using Ocelot.DownstreamRouteFinder; | ||||
| using Ocelot.DownstreamRouteFinder.UrlMatcher; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Responses; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace Ocelot.UnitTests.ClaimsBuilder | ||||
| namespace Ocelot.UnitTests.Claims | ||||
| { | ||||
|     using System; | ||||
|     using System.Collections.Generic; | ||||
|     using System.IO; | ||||
|     using System.Net.Http; | ||||
|     using Microsoft.AspNetCore.Hosting; | ||||
|     using Microsoft.AspNetCore.Http; | ||||
|     using Microsoft.AspNetCore.TestHost; | ||||
|     using Microsoft.Extensions.DependencyInjection; | ||||
|     using Moq; | ||||
|     using Ocelot.ClaimsBuilder; | ||||
|     using Ocelot.ClaimsBuilder.Middleware; | ||||
|     using Ocelot.Configuration; | ||||
|     using Ocelot.Configuration.Builder; | ||||
|     using Ocelot.DownstreamRouteFinder; | ||||
|     using Ocelot.DownstreamRouteFinder.UrlMatcher; | ||||
|     using Responses; | ||||
|     using TestStack.BDDfy; | ||||
|     using Xunit; | ||||
| 
 | ||||
|     public class ClaimsBuilderMiddlewareTests : IDisposable | ||||
|     { | ||||
|         private readonly Mock<IRequestScopedDataRepository> _scopedRepository; | ||||
| @@ -6,16 +6,15 @@ using Microsoft.Extensions.Primitives; | ||||
| using Moq; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Errors; | ||||
| using Ocelot.HeaderBuilder; | ||||
| using Ocelot.Headers; | ||||
| using Ocelot.Infrastructure.Claims.Parser; | ||||
| using Ocelot.Responses; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace Ocelot.UnitTests.HeaderBuilder | ||||
| namespace Ocelot.UnitTests.Headers | ||||
| { | ||||
|     using Ocelot.Infrastructure.Claims.Parser; | ||||
| 
 | ||||
|     public class AddHeadersToRequestTests | ||||
|     { | ||||
|         private readonly AddHeadersToRequest _addHeadersToRequest; | ||||
| @@ -11,14 +11,14 @@ using Ocelot.Configuration; | ||||
| using Ocelot.Configuration.Builder; | ||||
| using Ocelot.DownstreamRouteFinder; | ||||
| using Ocelot.DownstreamRouteFinder.UrlMatcher; | ||||
| using Ocelot.HeaderBuilder; | ||||
| using Ocelot.HeaderBuilder.Middleware; | ||||
| using Ocelot.Headers; | ||||
| using Ocelot.Headers.Middleware; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.Responses; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace Ocelot.UnitTests.HeaderBuilder | ||||
| namespace Ocelot.UnitTests.Headers | ||||
| { | ||||
|     public class HttpRequestHeadersBuilderMiddlewareTests : IDisposable | ||||
|     { | ||||
							
								
								
									
										153
									
								
								test/Ocelot.UnitTests/QueryStrings/AddQueriesToRequestTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								test/Ocelot.UnitTests/QueryStrings/AddQueriesToRequestTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Security.Claims; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Moq; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Errors; | ||||
| using Ocelot.Infrastructure.Claims.Parser; | ||||
| using Ocelot.QueryStrings; | ||||
| using Ocelot.Responses; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
|  | ||||
| namespace Ocelot.UnitTests.QueryStrings | ||||
| { | ||||
|     public class AddQueriesToRequestTests | ||||
|     { | ||||
|         private readonly AddQueriesToRequest _addQueriesToRequest; | ||||
|         private readonly Mock<IClaimsParser> _parser; | ||||
|         private List<ClaimToThing> _configuration; | ||||
|         private HttpContext _context; | ||||
|         private Response _result; | ||||
|         private Response<string> _claimValue; | ||||
|  | ||||
|         public AddQueriesToRequestTests() | ||||
|         { | ||||
|             _parser = new Mock<IClaimsParser>(); | ||||
|             _addQueriesToRequest = new AddQueriesToRequest(_parser.Object); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_add_queries_to_context() | ||||
|         { | ||||
|             var context = new DefaultHttpContext | ||||
|             { | ||||
|                 User = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> | ||||
|                 { | ||||
|                     new Claim("test", "data") | ||||
|                 })) | ||||
|             }; | ||||
|  | ||||
|             this.Given( | ||||
|                 x => x.GivenAClaimToThing(new List<ClaimToThing> | ||||
|                 { | ||||
|                     new ClaimToThing("query-key", "", "", 0) | ||||
|                 })) | ||||
|                 .Given(x => x.GivenHttpContext(context)) | ||||
|                 .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value"))) | ||||
|                 .When(x => x.WhenIAddQueriesToTheRequest()) | ||||
|                 .Then(x => x.ThenTheResultIsSuccess()) | ||||
|                 .And(x => x.ThenTheQueryIsAdded()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void if_query_exists_should_replace_it() | ||||
|         { | ||||
|             var context = new DefaultHttpContext | ||||
|             { | ||||
|                 User = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> | ||||
|                 { | ||||
|                     new Claim("test", "data") | ||||
|                 })), | ||||
|             }; | ||||
|  | ||||
|             context.Request.QueryString = context.Request.QueryString.Add("query-key", "initial"); | ||||
|  | ||||
|             this.Given( | ||||
|                 x => x.GivenAClaimToThing(new List<ClaimToThing> | ||||
|                 { | ||||
|                     new ClaimToThing("query-key", "", "", 0) | ||||
|                 })) | ||||
|                 .Given(x => x.GivenHttpContext(context)) | ||||
|                 .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value"))) | ||||
|                 .When(x => x.WhenIAddQueriesToTheRequest()) | ||||
|                 .Then(x => x.ThenTheResultIsSuccess()) | ||||
|                 .And(x => x.ThenTheQueryIsAdded()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_return_error() | ||||
|         { | ||||
|             this.Given( | ||||
|                x => x.GivenAClaimToThing(new List<ClaimToThing> | ||||
|                { | ||||
|                     new ClaimToThing("", "", "", 0) | ||||
|                })) | ||||
|                .Given(x => x.GivenHttpContext(new DefaultHttpContext())) | ||||
|                .And(x => x.GivenTheClaimParserReturns(new ErrorResponse<string>(new List<Error> | ||||
|                { | ||||
|                    new AnyError() | ||||
|                }))) | ||||
|                .When(x => x.WhenIAddQueriesToTheRequest()) | ||||
|                .Then(x => x.ThenTheResultIsError()) | ||||
|                .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheQueryIsAdded() | ||||
|         { | ||||
|             var query = _context.Request.Query.First(x => x.Key == "query-key"); | ||||
|             query.Value.First().ShouldBe(_claimValue.Data); | ||||
|         } | ||||
|  | ||||
|         private void GivenAClaimToThing(List<ClaimToThing> configuration) | ||||
|         { | ||||
|             _configuration = configuration; | ||||
|         } | ||||
|  | ||||
|         private void GivenHttpContext(HttpContext context) | ||||
|         { | ||||
|             _context = context; | ||||
|         } | ||||
|  | ||||
|         private void GivenTheClaimParserReturns(Response<string> claimValue) | ||||
|         { | ||||
|             _claimValue = claimValue; | ||||
|             _parser | ||||
|                 .Setup( | ||||
|                     x => | ||||
|                         x.GetValue(It.IsAny<IEnumerable<Claim>>(),  | ||||
|                         It.IsAny<string>(),  | ||||
|                         It.IsAny<string>(), | ||||
|                         It.IsAny<int>())) | ||||
|                 .Returns(_claimValue); | ||||
|         } | ||||
|  | ||||
|         private void WhenIAddQueriesToTheRequest() | ||||
|         { | ||||
|             _result = _addQueriesToRequest.SetQueriesOnContext(_configuration, _context); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheResultIsSuccess() | ||||
|         { | ||||
|             _result.IsError.ShouldBe(false); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheResultIsError() | ||||
|         { | ||||
|  | ||||
|             _result.IsError.ShouldBe(true); | ||||
|         } | ||||
|  | ||||
|         class AnyError : Error | ||||
|         { | ||||
|             public AnyError()  | ||||
|                 : base("blahh", OcelotErrorCode.UnknownError) | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,111 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Net.Http; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.AspNetCore.TestHost; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Moq; | ||||
| using Ocelot.Configuration; | ||||
| using Ocelot.Configuration.Builder; | ||||
| using Ocelot.DownstreamRouteFinder; | ||||
| using Ocelot.DownstreamRouteFinder.UrlMatcher; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.QueryStrings; | ||||
| using Ocelot.QueryStrings.Middleware; | ||||
| using Ocelot.Responses; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
|  | ||||
| namespace Ocelot.UnitTests.QueryStrings | ||||
| { | ||||
|     public class QueryStringBuilderMiddlewareTests : IDisposable | ||||
|     { | ||||
|         private readonly Mock<IRequestScopedDataRepository> _scopedRepository; | ||||
|         private readonly Mock<IAddQueriesToRequest> _addQueries; | ||||
|         private readonly string _url; | ||||
|         private readonly TestServer _server; | ||||
|         private readonly HttpClient _client; | ||||
|         private Response<DownstreamRoute> _downstreamRoute; | ||||
|         private HttpResponseMessage _result; | ||||
|  | ||||
|         public QueryStringBuilderMiddlewareTests() | ||||
|         { | ||||
|             _url = "http://localhost:51879"; | ||||
|             _scopedRepository = new Mock<IRequestScopedDataRepository>(); | ||||
|             _addQueries = new Mock<IAddQueriesToRequest>(); | ||||
|             var builder = new WebHostBuilder() | ||||
|               .ConfigureServices(x => | ||||
|               { | ||||
|                   x.AddSingleton(_addQueries.Object); | ||||
|                   x.AddSingleton(_scopedRepository.Object); | ||||
|               }) | ||||
|               .UseUrls(_url) | ||||
|               .UseKestrel() | ||||
|               .UseContentRoot(Directory.GetCurrentDirectory()) | ||||
|               .UseIISIntegration() | ||||
|               .UseUrls(_url) | ||||
|               .Configure(app => | ||||
|               { | ||||
|                   app.UseQueryStringBuilderMiddleware(); | ||||
|               }); | ||||
|  | ||||
|             _server = new TestServer(builder); | ||||
|             _client = _server.CreateClient(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void happy_path() | ||||
|         { | ||||
|             var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), | ||||
|                 new ReRouteBuilder() | ||||
|                     .WithDownstreamTemplate("any old string") | ||||
|                     .WithClaimsToQueries(new List<ClaimToThing> | ||||
|                     { | ||||
|                         new ClaimToThing("UserId", "Subject", "", 0) | ||||
|                     }) | ||||
|                     .Build()); | ||||
|  | ||||
|             this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) | ||||
|                 .And(x => x.GivenTheAddHeadersToRequestReturns()) | ||||
|                 .When(x => x.WhenICallTheMiddleware()) | ||||
|                 .Then(x => x.ThenTheAddHeadersToRequestIsCalledCorrectly()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheAddHeadersToRequestReturns() | ||||
|         { | ||||
|             _addQueries | ||||
|                 .Setup(x => x.SetQueriesOnContext(It.IsAny<List<ClaimToThing>>(),  | ||||
|                 It.IsAny<HttpContext>())) | ||||
|                 .Returns(new OkResponse()); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheAddHeadersToRequestIsCalledCorrectly() | ||||
|         { | ||||
|             _addQueries | ||||
|                 .Verify(x => x.SetQueriesOnContext(It.IsAny<List<ClaimToThing>>(), | ||||
|                 It.IsAny<HttpContext>()), Times.Once); | ||||
|         } | ||||
|  | ||||
|         private void WhenICallTheMiddleware() | ||||
|         { | ||||
|             _result = _client.GetAsync(_url).Result; | ||||
|         } | ||||
|  | ||||
|         private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) | ||||
|         { | ||||
|             _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute); | ||||
|             _scopedRepository | ||||
|                 .Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>())) | ||||
|                 .Returns(_downstreamRoute); | ||||
|         } | ||||
|  | ||||
|         public void Dispose() | ||||
|         { | ||||
|             _client.Dispose(); | ||||
|             _server.Dispose(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -8,14 +8,13 @@ using Microsoft.AspNetCore.TestHost; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Moq; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.RequestBuilder; | ||||
| using Ocelot.RequestBuilder.Builder; | ||||
| using Ocelot.RequestBuilder.Middleware; | ||||
| using Ocelot.Request.Builder; | ||||
| using Ocelot.Request.Middleware; | ||||
| using Ocelot.Responses; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace Ocelot.UnitTests.RequestBuilder | ||||
| namespace Ocelot.UnitTests.Request | ||||
| { | ||||
|     public class HttpRequestBuilderMiddlewareTests : IDisposable | ||||
|     { | ||||
| @@ -25,7 +24,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|         private readonly TestServer _server; | ||||
|         private readonly HttpClient _client; | ||||
|         private HttpResponseMessage _result; | ||||
|         private OkResponse<Request> _request; | ||||
|         private OkResponse<Ocelot.Request.Request> _request; | ||||
|         private OkResponse<string> _downstreamUrl; | ||||
| 
 | ||||
|         public HttpRequestBuilderMiddlewareTests() | ||||
| @@ -58,15 +57,15 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|         public void happy_path() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) | ||||
|                 .And(x => x.GivenTheRequestBuilderReturns(new Request(new HttpRequestMessage(), new CookieContainer()))) | ||||
|                 .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), new CookieContainer()))) | ||||
|                 .When(x => x.WhenICallTheMiddleware()) | ||||
|                 .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
|         private void GivenTheRequestBuilderReturns(Request request) | ||||
|         private void GivenTheRequestBuilderReturns(Ocelot.Request.Request request) | ||||
|         { | ||||
|             _request = new OkResponse<Request>(request); | ||||
|             _request = new OkResponse<Ocelot.Request.Request>(request); | ||||
|             _requestBuilder | ||||
|                 .Setup(x => x.Build(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Stream>(), It.IsAny<IHeaderDictionary>(), | ||||
|                 It.IsAny<IRequestCookieCollection>(), It.IsAny<QueryString>(), It.IsAny<string>())) | ||||
| @@ -5,14 +5,13 @@ using System.Net; | ||||
| using System.Net.Http; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.AspNetCore.Http.Internal; | ||||
| using Ocelot.RequestBuilder; | ||||
| using Ocelot.RequestBuilder.Builder; | ||||
| using Ocelot.Request.Builder; | ||||
| using Ocelot.Responses; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| 
 | ||||
| namespace Ocelot.UnitTests.RequestBuilder | ||||
| namespace Ocelot.UnitTests.Request | ||||
| { | ||||
|     public class RequestBuilderTests | ||||
|     { | ||||
| @@ -24,7 +23,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|         private QueryString _query; | ||||
|         private string _contentType; | ||||
|         private readonly IRequestBuilder _requestBuilder; | ||||
|         private Response<Request> _result; | ||||
|         private Response<Ocelot.Request.Request> _result; | ||||
| 
 | ||||
|         public RequestBuilderTests() | ||||
|         { | ||||
| @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.TestHost; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Moq; | ||||
| using Ocelot.Infrastructure.RequestData; | ||||
| using Ocelot.RequestBuilder; | ||||
| using Ocelot.Requester; | ||||
| using Ocelot.Requester.Middleware; | ||||
| using Ocelot.Responder; | ||||
| @@ -27,7 +26,7 @@ namespace Ocelot.UnitTests.Requester | ||||
|         private readonly HttpClient _client; | ||||
|         private HttpResponseMessage _result; | ||||
|         private OkResponse<HttpResponseMessage> _response; | ||||
|         private OkResponse<Request> _request; | ||||
|         private OkResponse<Ocelot.Request.Request> _request; | ||||
|         private readonly Mock<IHttpResponder> _responder; | ||||
|  | ||||
|         public HttpRequesterMiddlewareTests() | ||||
| @@ -61,7 +60,7 @@ namespace Ocelot.UnitTests.Requester | ||||
|         [Fact] | ||||
|         public void happy_path() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheRequestIs(new Request(new HttpRequestMessage(),new CookieContainer()))) | ||||
|             this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),new CookieContainer()))) | ||||
|                 .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) | ||||
|                 .And(x => x.GivenTheResponderReturns()) | ||||
|                 .When(x => x.WhenICallTheMiddleware()) | ||||
| @@ -73,7 +72,7 @@ namespace Ocelot.UnitTests.Requester | ||||
|         { | ||||
|             _response = new OkResponse<HttpResponseMessage>(response); | ||||
|             _requester | ||||
|                 .Setup(x => x.GetResponse(It.IsAny<Request>())) | ||||
|                 .Setup(x => x.GetResponse(It.IsAny<Ocelot.Request.Request>())) | ||||
|                 .ReturnsAsync(_response); | ||||
|         } | ||||
|  | ||||
| @@ -95,11 +94,11 @@ namespace Ocelot.UnitTests.Requester | ||||
|             _result = _client.GetAsync(_url).Result; | ||||
|         } | ||||
|  | ||||
|         private void GivenTheRequestIs(Request request) | ||||
|         private void GivenTheRequestIs(Ocelot.Request.Request request) | ||||
|         { | ||||
|             _request = new OkResponse<Request>(request); | ||||
|             _request = new OkResponse<Ocelot.Request.Request>(request); | ||||
|             _scopedRepository | ||||
|                 .Setup(x => x.Get<Request>(It.IsAny<string>())) | ||||
|                 .Setup(x => x.Get<Ocelot.Request.Request>(It.IsAny<string>())) | ||||
|                 .Returns(_request); | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 TomPallister
					TomPallister