From e91da1ac2331fd63dbd83a6860c3ef27adeb33fe Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Thu, 4 May 2017 10:56:16 +0100 Subject: [PATCH 01/10] Add the possibility of set mutiple verbs in the UpstreamHttpMethod property. Add UnitTests and AcceptanceTests to try this feature. --- .../Configuration/Builder/ReRouteBuilder.cs | 7 +- src/Ocelot/Configuration/ReRoute.cs | 4 +- .../Finder/DownstreamRouteFinder.cs | 2 +- test/Ocelot.AcceptanceTests/RoutingTests.cs | 56 ++++++++++++ .../DownstreamRouteFinderTests.cs | 89 +++++++++++++++++++ 5 files changed, 152 insertions(+), 6 deletions(-) diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 30d9d87a..6839ed13 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Net.Http; using Ocelot.Values; +using System.Linq; namespace Ocelot.Configuration.Builder { @@ -11,7 +12,7 @@ namespace Ocelot.Configuration.Builder private string _downstreamPathTemplate; private string _upstreamTemplate; private string _upstreamTemplatePattern; - private string _upstreamHttpMethod; + private List _upstreamHttpMethod; private bool _isAuthenticated; private List _configHeaderExtractorProperties; private List _claimToClaims; @@ -68,7 +69,7 @@ namespace Ocelot.Configuration.Builder } public ReRouteBuilder WithUpstreamHttpMethod(string input) { - _upstreamHttpMethod = input; + _upstreamHttpMethod = string.IsNullOrWhiteSpace(input) ? new List() : input.Split(',').Select(x => new HttpMethod(x.Trim())).ToList(); return this; } public ReRouteBuilder WithIsAuthenticated(bool input) @@ -180,7 +181,7 @@ namespace Ocelot.Configuration.Builder return new ReRoute( new PathTemplate(_downstreamPathTemplate), new PathTemplate(_upstreamTemplate), - new HttpMethod(_upstreamHttpMethod), + _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, _authenticationOptions, diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index bba8c925..a6673d09 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -8,7 +8,7 @@ namespace Ocelot.Configuration { public ReRoute(PathTemplate downstreamPathTemplate, PathTemplate upstreamPathTemplate, - HttpMethod upstreamHttpMethod, + List upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, @@ -64,7 +64,7 @@ namespace Ocelot.Configuration public PathTemplate DownstreamPathTemplate { get; private set; } public PathTemplate UpstreamPathTemplate { get; private set; } public string UpstreamTemplatePattern { get; private set; } - public HttpMethod UpstreamHttpMethod { get; private set; } + public List UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } public bool IsAuthorised { get; private set; } public AuthenticationOptions AuthenticationOptions { get; private set; } diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index 82a5e7c5..bf0d5a52 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -26,7 +26,7 @@ namespace Ocelot.DownstreamRouteFinder.Finder { var configuration = await _configProvider.Get(); - var applicableReRoutes = configuration.Data.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod.Method.ToLower(), upstreamHttpMethod.ToLower(), StringComparison.CurrentCultureIgnoreCase)); + var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); foreach (var reRoute in applicableReRoutes) { diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 99c11877..ffefd277 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -319,6 +319,62 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_201_with_simple_url_and_multiple_upstream_http_method() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamHost = "localhost", + DownstreamPort = 51879, + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = "Get, Post", + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 201, string.Empty)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } + + [Fact] + public void should_return_response_200_with_simple_url_and_any_upstream_http_method() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamHost = "localhost", + DownstreamPort = 51879, + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = "", + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _builder = new WebHostBuilder() diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 0d272c63..64c20af0 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -157,6 +157,95 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } + [Fact] + public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Get, Post") + .WithUpstreamTemplatePattern("") + .Build() + }, string.Empty + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod("Post") + .Build() + ))) + .BDDfy(); + } + + [Fact] + public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("") + .WithUpstreamTemplatePattern("") + .Build() + }, string.Empty + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod("Post") + .Build() + ))) + .BDDfy(); + } + + [Fact] + public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Get, Patch, Delete") + .WithUpstreamTemplatePattern("") + .Build() + }, string.Empty + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenAnErrorResponseIsReturned()) + .And(x => x.ThenTheUrlMatcherIsNotCalled()) + .BDDfy(); + } + private void GivenTheTemplateVariableAndNameFinderReturns(Response> response) { _finder From 24f7b9a171f986bfa71c9a477f2daa339ceb7619 Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Fri, 5 May 2017 11:47:28 +0100 Subject: [PATCH 02/10] UpstreamHttpMethod property (of class FileReRoute) changes from string to List. --- .../Configuration/Builder/ReRouteBuilder.cs | 7 +- src/Ocelot/Configuration/File/FileReRoute.cs | 3 +- .../Validator/FileConfigurationValidator.cs | 44 +- .../AuthenticationTests.cs | 14 +- .../AuthorisationTests.cs | 4 +- test/Ocelot.AcceptanceTests/CachingTests.cs | 4 +- .../CaseSensitiveRoutingTests.cs | 12 +- .../ClaimsToHeadersForwardingTests.cs | 2 +- .../ClaimsToQueryStringForwardingTests.cs | 2 +- .../ClientRateLimitTests.cs | 4 +- .../ConfigurationInConsulTests.cs | 3 +- .../CustomMiddlewareTests.cs | 14 +- test/Ocelot.AcceptanceTests/QoSTests.cs | 6 +- test/Ocelot.AcceptanceTests/RequestIdTests.cs | 7 +- .../ReturnsErrorTests.cs | 2 +- test/Ocelot.AcceptanceTests/RoutingTests.cs | 27 +- .../ServiceDiscoveryTests.cs | 2 +- .../AdministrationTests.cs | 12 +- .../ThreadSafeHeadersTests.cs | 2 +- test/Ocelot.ManualTest/configuration.json | 614 +++++++++--------- .../AuthenticationMiddlewareTests.cs | 2 +- .../AuthorisationMiddlewareTests.cs | 2 +- .../Cache/OutputCacheMiddlewareTests.cs | 2 +- .../Claims/ClaimsBuilderMiddlewareTests.cs | 2 +- .../FileConfigurationCreatorTests.cs | 38 +- .../InMemoryConfigurationRepositoryTests.cs | 2 +- .../DownstreamRouteFinderMiddlewareTests.cs | 2 +- .../DownstreamRouteFinderTests.cs | 26 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 2 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 18 +- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 2 +- .../LoadBalancer/LoadBalancerFactoryTests.cs | 9 +- .../LoadBalancerMiddlewareTests.cs | 6 +- .../QueryStringBuilderMiddlewareTests.cs | 2 +- .../ClientRateLimitMiddlewareTests.cs | 4 +- .../HttpRequestBuilderMiddlewareTests.cs | 2 +- .../RequestId/RequestIdMiddlewareTests.cs | 4 +- .../Requester/QoSProviderFactoryTests.cs | 5 +- 38 files changed, 464 insertions(+), 451 deletions(-) diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 6839ed13..852c4870 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -67,11 +67,13 @@ namespace Ocelot.Configuration.Builder _upstreamTemplatePattern = input; return this; } - public ReRouteBuilder WithUpstreamHttpMethod(string input) + + public ReRouteBuilder WithUpstreamHttpMethod(List input) { - _upstreamHttpMethod = string.IsNullOrWhiteSpace(input) ? new List() : input.Split(',').Select(x => new HttpMethod(x.Trim())).ToList(); + _upstreamHttpMethod = (input.Count == 0) ? new List() : input.Select(x => new HttpMethod(x.Trim())).ToList(); return this; } + public ReRouteBuilder WithIsAuthenticated(bool input) { _isAuthenticated = input; @@ -144,7 +146,6 @@ namespace Ocelot.Configuration.Builder return this; } - public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey) { _loadBalancerKey = loadBalancerKey; diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index 07562653..59483aee 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -6,6 +6,7 @@ namespace Ocelot.Configuration.File { public FileReRoute() { + UpstreamHttpMethod = new List(); AddHeadersToRequest = new Dictionary(); AddClaimsToRequest = new Dictionary(); RouteClaimsRequirement = new Dictionary(); @@ -18,7 +19,7 @@ namespace Ocelot.Configuration.File public string DownstreamPathTemplate { get; set; } public string UpstreamPathTemplate { get; set; } - public string UpstreamHttpMethod { get; set; } + public List UpstreamHttpMethod { get; set; } public FileAuthenticationOptions AuthenticationOptions { get; set; } public Dictionary AddHeadersToRequest { get; set; } public Dictionary AddClaimsToRequest { get; set; } diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs index 98301ab4..b137647b 100644 --- a/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs +++ b/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs @@ -12,7 +12,7 @@ namespace Ocelot.Configuration.Validator { public Response IsValid(FileConfiguration configuration) { - var result = CheckForDupliateReRoutes(configuration); + var result = CheckForDuplicateReRoutes(configuration); if (result.IsError) { @@ -91,25 +91,41 @@ namespace Ocelot.Configuration.Validator return new ConfigurationValidationResult(false, errors); } - private ConfigurationValidationResult CheckForDupliateReRoutes(FileConfiguration configuration) - { - var hasDupes = configuration.ReRoutes - .GroupBy(x => new { x.UpstreamPathTemplate, x.UpstreamHttpMethod }).Any(x => x.Skip(1).Any()); + private ConfigurationValidationResult CheckForDuplicateReRoutes(FileConfiguration configuration) + { + var duplicatedUpstreamPathTemplates = new List(); - if (!hasDupes) + var distinctUpstreamPathTemplates = configuration.ReRoutes.Select(x => x.UpstreamPathTemplate).Distinct(); + + foreach (string upstreamPathTemplate in distinctUpstreamPathTemplates) + { + var reRoutesWithUpstreamPathTemplate = configuration.ReRoutes.Where(x => x.UpstreamPathTemplate == upstreamPathTemplate); + + var hasEmptyListToAllowAllHttpVerbs = reRoutesWithUpstreamPathTemplate.Where(x => x.UpstreamHttpMethod.Count() == 0).Any(); + var hasDuplicateEmptyListToAllowAllHttpVerbs = reRoutesWithUpstreamPathTemplate.Where(x => x.UpstreamHttpMethod.Count() == 0).Count() > 1; + var hasSpecificHttpVerbs = reRoutesWithUpstreamPathTemplate.Where(x => x.UpstreamHttpMethod.Count() > 0).Any(); + var hasDuplicateSpecificHttpVerbs = reRoutesWithUpstreamPathTemplate.SelectMany(x => x.UpstreamHttpMethod).GroupBy(x => x.ToLower()).SelectMany(x => x.Skip(1)).Any(); + + if (hasDuplicateEmptyListToAllowAllHttpVerbs || hasDuplicateSpecificHttpVerbs || (hasEmptyListToAllowAllHttpVerbs && hasSpecificHttpVerbs)) + { + duplicatedUpstreamPathTemplates.Add(upstreamPathTemplate); + } + } + + if (duplicatedUpstreamPathTemplates.Count() == 0) { return new ConfigurationValidationResult(false); } + else + { + var errors = duplicatedUpstreamPathTemplates + .Select(d => new DownstreamPathTemplateAlreadyUsedError(string.Format("Duplicate DownstreamPath: {0}", d))) + .Cast() + .ToList(); - var dupes = configuration.ReRoutes.GroupBy(x => new { x.UpstreamPathTemplate, x.UpstreamHttpMethod }) - .Where(x => x.Skip(1).Any()); + return new ConfigurationValidationResult(true, errors); + } - var errors = dupes - .Select(d => new DownstreamPathTemplateAlreadyUsedError(string.Format("Duplicate DownstreamPath: {0}", d.Key.UpstreamPathTemplate))) - .Cast() - .ToList(); - - return new ConfigurationValidationResult(true, errors); } } } diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 6f1609f6..32e72a18 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -48,7 +48,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = _downstreamServiceHost, DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Post", + UpstreamHttpMethod = new List { "Post" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), @@ -86,7 +86,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = _downstreamServiceHost, DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Post", + UpstreamHttpMethod = new List { "Post" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), @@ -124,7 +124,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = _downstreamServiceHost, DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), @@ -164,8 +164,8 @@ namespace Ocelot.AcceptanceTests DownstreamHost = _downstreamServiceHost, DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Post", - + UpstreamHttpMethod = new List { "Post" }, + AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), @@ -205,8 +205,8 @@ namespace Ocelot.AcceptanceTests DownstreamHost = _downstreamServiceHost, DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Post", - AuthenticationOptions = new FileAuthenticationOptions + UpstreamHttpMethod = new List { "Post" }, + AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), Provider = "IdentityServer", diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 3b1609c9..2e4a446e 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -42,7 +42,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), @@ -99,7 +99,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List(), diff --git a/test/Ocelot.AcceptanceTests/CachingTests.cs b/test/Ocelot.AcceptanceTests/CachingTests.cs index a8364855..888cf151 100644 --- a/test/Ocelot.AcceptanceTests/CachingTests.cs +++ b/test/Ocelot.AcceptanceTests/CachingTests.cs @@ -36,7 +36,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, FileCacheOptions = new FileCacheOptions { TtlSeconds = 100 @@ -72,7 +72,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, FileCacheOptions = new FileCacheOptions { TtlSeconds = 1 diff --git a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs index 85e8fd68..740bf512 100644 --- a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs @@ -35,7 +35,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -62,7 +62,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = false, } } @@ -90,7 +90,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, } } @@ -118,7 +118,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/PRODUCTS/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, } } @@ -146,7 +146,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, } } @@ -174,7 +174,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/PRODUCTS/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, } } diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 702ecd0d..c2caa19e 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -56,7 +56,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index 2cca7048..f2f1ca66 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -56,7 +56,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, AuthenticationOptions = new FileAuthenticationOptions { AllowedScopes = new List diff --git a/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs b/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs index 959777c6..8416a66d 100644 --- a/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs +++ b/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs @@ -47,7 +47,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/api/ClientRateLimit", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, RequestIdKey = _steps.RequestIdKey, RateLimitOptions = new FileRateLimitRule() @@ -102,7 +102,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/api/ClientRateLimit", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, RequestIdKey = _steps.RequestIdKey, RateLimitOptions = new FileRateLimitRule() diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index b2dfdc80..0ab4cc6a 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -44,8 +44,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51779, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } }, GlobalConfiguration = new FileGlobalConfiguration() diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs index 7d33febb..6b45c6f8 100644 --- a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -50,7 +50,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -87,8 +87,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -125,8 +124,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -163,7 +161,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -200,7 +198,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -237,7 +235,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; diff --git a/test/Ocelot.AcceptanceTests/QoSTests.cs b/test/Ocelot.AcceptanceTests/QoSTests.cs index 0eb3d8a4..98c0540e 100644 --- a/test/Ocelot.AcceptanceTests/QoSTests.cs +++ b/test/Ocelot.AcceptanceTests/QoSTests.cs @@ -39,7 +39,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, QoSOptions = new FileQoSOptions { ExceptionsAllowedBeforeBreaking = 1, @@ -83,7 +83,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, QoSOptions = new FileQoSOptions { ExceptionsAllowedBeforeBreaking = 1, @@ -98,7 +98,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51880, UpstreamPathTemplate = "working", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; diff --git a/test/Ocelot.AcceptanceTests/RequestIdTests.cs b/test/Ocelot.AcceptanceTests/RequestIdTests.cs index 46a5fc13..1c87bc9c 100644 --- a/test/Ocelot.AcceptanceTests/RequestIdTests.cs +++ b/test/Ocelot.AcceptanceTests/RequestIdTests.cs @@ -38,7 +38,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, RequestIdKey = _steps.RequestIdKey, } } @@ -66,8 +66,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -96,7 +95,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } }, GlobalConfiguration = new FileGlobalConfiguration diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index 868cb39f..86815e98 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -31,7 +31,7 @@ namespace Ocelot.AcceptanceTests { DownstreamPathTemplate = "/", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, DownstreamPort = 53876, DownstreamScheme = "http", DownstreamHost = "localhost" diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index ffefd277..b32c4690 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -45,7 +45,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -73,8 +73,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -102,8 +101,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost/", DownstreamPort = 51879, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -131,8 +129,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/products/", - UpstreamHttpMethod = "Get", - + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -160,7 +157,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/products", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -188,7 +185,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, QoSOptions = new FileQoSOptions() { ExceptionsAllowedBeforeBreaking = 3, @@ -221,7 +218,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -249,7 +246,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, DownstreamScheme = "http", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Post", + UpstreamHttpMethod = new List { "Post" }, } } }; @@ -277,7 +274,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", DownstreamPort = 51879, - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -305,7 +302,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/myApp1Name/api/{urlPath}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; @@ -333,7 +330,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, DownstreamScheme = "http", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get, Post", + UpstreamHttpMethod = new List { "Get", "Post" }, } } }; @@ -361,7 +358,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, DownstreamScheme = "http", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "", + UpstreamHttpMethod = new List(), } } }; diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs index fcf75b14..943e8a23 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs @@ -69,7 +69,7 @@ namespace Ocelot.AcceptanceTests DownstreamPathTemplate = "/", DownstreamScheme = "http", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ServiceName = serviceName, LoadBalancer = "LeastConnection", } diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 642493bb..2fa2c05c 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -94,7 +94,7 @@ namespace Ocelot.IntegrationTests DownstreamPort = 80, DownstreamScheme = "https", DownstreamPathTemplate = "/", - UpstreamHttpMethod = "get", + UpstreamHttpMethod = new List { "get" }, UpstreamPathTemplate = "/" }, new FileReRoute() @@ -103,7 +103,7 @@ namespace Ocelot.IntegrationTests DownstreamPort = 80, DownstreamScheme = "https", DownstreamPathTemplate = "/", - UpstreamHttpMethod = "get", + UpstreamHttpMethod = new List { "get" }, UpstreamPathTemplate = "/test" } } @@ -136,7 +136,7 @@ namespace Ocelot.IntegrationTests DownstreamPort = 80, DownstreamScheme = "https", DownstreamPathTemplate = "/", - UpstreamHttpMethod = "get", + UpstreamHttpMethod = new List { "get" }, UpstreamPathTemplate = "/" }, new FileReRoute() @@ -145,7 +145,7 @@ namespace Ocelot.IntegrationTests DownstreamPort = 80, DownstreamScheme = "https", DownstreamPathTemplate = "/", - UpstreamHttpMethod = "get", + UpstreamHttpMethod = new List { "get" }, UpstreamPathTemplate = "/test" } } @@ -165,7 +165,7 @@ namespace Ocelot.IntegrationTests DownstreamPort = 80, DownstreamScheme = "http", DownstreamPathTemplate = "/geoffrey", - UpstreamHttpMethod = "get", + UpstreamHttpMethod = new List { "get" }, UpstreamPathTemplate = "/" }, new FileReRoute() @@ -174,7 +174,7 @@ namespace Ocelot.IntegrationTests DownstreamPort = 443, DownstreamScheme = "https", DownstreamPathTemplate = "/blooper/{productId}", - UpstreamHttpMethod = "post", + UpstreamHttpMethod = new List { "post" }, UpstreamPathTemplate = "/test" } } diff --git a/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs b/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs index 191dea47..2512a87d 100644 --- a/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs +++ b/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs @@ -55,7 +55,7 @@ namespace Ocelot.IntegrationTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } } }; diff --git a/test/Ocelot.ManualTest/configuration.json b/test/Ocelot.ManualTest/configuration.json index 9e1f394b..765326cf 100644 --- a/test/Ocelot.ManualTest/configuration.json +++ b/test/Ocelot.ManualTest/configuration.json @@ -1,311 +1,311 @@ { - "ReRoutes": [ - { - "DownstreamPathTemplate": "/", - "DownstreamScheme": "http", - "DownstreamHost": "localhost", - "DownstreamPort": 52876, - "UpstreamPathTemplate": "/identityserverexample", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "AuthenticationOptions": { - "Provider": "IdentityServer", - "ProviderRootUrl": "http://localhost:52888", - "ApiName": "api", - "AllowedScopes": [ - "openid", - "offline_access" - ], - "ApiSecret": "secret" - }, - "AddHeadersToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - "AddClaimsToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - "AddQueriesToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - "RouteClaimsRequirement": { - "UserType": "registered" - }, - "RequestIdKey": "OcRequestId" - }, - { - "DownstreamPathTemplate": "/posts", - "DownstreamScheme": "https", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 443, - "UpstreamPathTemplate": "/posts", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/posts/{postId}/comments", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts/{postId}/comments", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/comments", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/comments", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/posts", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts", - "UpstreamHttpMethod": "Post", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Put", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Patch", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Delete", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/api/products", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/products", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/products/{productId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/products/{productId}", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/products", - "DownstreamScheme": "http", - "DownstreamHost": "products20161126090340.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/products", - "UpstreamHttpMethod": "Post", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - } - }, - { - "DownstreamPathTemplate": "/api/products/{productId}", - "DownstreamScheme": "http", - "DownstreamHost": "products20161126090340.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/products/{productId}", - "UpstreamHttpMethod": "Put", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/products/{productId}", - "DownstreamScheme": "http", - "DownstreamHost": "products20161126090340.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/products/{productId}", - "UpstreamHttpMethod": "Delete", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/customers", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers/{customerId}", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/customers/{customerId}", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/customers", - "UpstreamHttpMethod": "Post", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers/{customerId}", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/customers/{customerId}", - "UpstreamHttpMethod": "Put", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers/{customerId}", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/customers/{customerId}", - "UpstreamHttpMethod": "Delete", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/posts", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/posts/", - "UpstreamHttpMethod": "Get", - "QoSOptions": { - "ExceptionsAllowedBeforeBreaking": 3, - "DurationOfBreak": 10, - "TimeoutValue": 5000 - }, - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/", - "DownstreamScheme": "http", - "DownstreamHost": "www.bbc.co.uk", - "DownstreamPort": 80, - "UpstreamPathTemplate": "/bbc/", - "UpstreamHttpMethod": "Get" - } - ], + "ReRoutes": [ + { + "DownstreamPathTemplate": "/", + "DownstreamScheme": "http", + "DownstreamHost": "localhost", + "DownstreamPort": 52876, + "UpstreamPathTemplate": "/identityserverexample", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "AuthenticationOptions": { + "Provider": "IdentityServer", + "ProviderRootUrl": "http://localhost:52888", + "ApiName": "api", + "AllowedScopes": [ + "openid", + "offline_access" + ], + "ApiSecret": "secret" + }, + "AddHeadersToRequest": { + "CustomerId": "Claims[CustomerId] > value", + "LocationId": "Claims[LocationId] > value", + "UserType": "Claims[sub] > value[0] > |", + "UserId": "Claims[sub] > value[1] > |" + }, + "AddClaimsToRequest": { + "CustomerId": "Claims[CustomerId] > value", + "LocationId": "Claims[LocationId] > value", + "UserType": "Claims[sub] > value[0] > |", + "UserId": "Claims[sub] > value[1] > |" + }, + "AddQueriesToRequest": { + "CustomerId": "Claims[CustomerId] > value", + "LocationId": "Claims[LocationId] > value", + "UserType": "Claims[sub] > value[0] > |", + "UserId": "Claims[sub] > value[1] > |" + }, + "RouteClaimsRequirement": { + "UserType": "registered" + }, + "RequestIdKey": "OcRequestId" + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "https", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 443, + "UpstreamPathTemplate": "/posts", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts/{postId}", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts/{postId}/comments", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/comments", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts", + "UpstreamHttpMethod": [ "Post" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts/{postId}", + "UpstreamHttpMethod": [ "Put" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts/{postId}", + "UpstreamHttpMethod": [ "Patch" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts/{postId}", + "UpstreamHttpMethod": [ "Delete" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/products", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/products/{productId}", + "UpstreamHttpMethod": [ "Get" ], + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/products", + "UpstreamHttpMethod": [ "Post" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/products/{productId}", + "UpstreamHttpMethod": [ "Put" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/products/{productId}", + "UpstreamHttpMethod": [ "Delete" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/customers", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/customers/{customerId}", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/customers", + "UpstreamHttpMethod": [ "Post" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/customers/{customerId}", + "UpstreamHttpMethod": [ "Put" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/customers/{customerId}", + "UpstreamHttpMethod": [ "Delete" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/posts/", + "UpstreamHttpMethod": [ "Get" ], + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/", + "DownstreamScheme": "http", + "DownstreamHost": "www.bbc.co.uk", + "DownstreamPort": 80, + "UpstreamPathTemplate": "/bbc/", + "UpstreamHttpMethod": [ "Get" ], + } + ], "GlobalConfiguration": { "RequestIdKey": "OcRequestId", diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index f60eb83c..be709dff 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Authentication public void should_call_next_middleware_if_route_is_not_authenticated() { this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder() - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheUserIsAuthenticated()) diff --git a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs index 35435fc2..9a890089 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs @@ -66,7 +66,7 @@ namespace Ocelot.UnitTests.Authorization this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder() .WithIsAuthorised(true) - .WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .And(x => x.GivenTheAuthServiceReturns(new OkResponse(true))) .When(x => x.WhenICallTheMiddleware()) diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index 6537c684..dfc0220f 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -91,7 +91,7 @@ namespace Ocelot.UnitTests.Cache var reRoute = new ReRouteBuilder() .WithIsCached(true) .WithCacheOptions(new CacheOptions(100)) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build(); var downstreamRoute = new DownstreamRoute(new List(), reRoute); diff --git a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs index 90a16b17..d17d7978 100644 --- a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs @@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Claims { new ClaimToThing("sub", "UserType", "|", 0) }) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index 5f8a37ad..bd8c46d3 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -84,7 +84,7 @@ namespace Ocelot.UnitTests.Configuration DownstreamHost = "127.0.0.1", UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } }, })) @@ -117,7 +117,7 @@ namespace Ocelot.UnitTests.Configuration DownstreamHost = "127.0.0.1", UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, QoSOptions = new FileQoSOptions { TimeoutValue = 1, @@ -153,7 +153,7 @@ namespace Ocelot.UnitTests.Configuration DownstreamHost = "127.0.0.1", UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } }, })) @@ -181,7 +181,7 @@ namespace Ocelot.UnitTests.Configuration DownstreamHost = "127.0.0.1", UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } }, })) @@ -194,7 +194,7 @@ namespace Ocelot.UnitTests.Configuration .WithDownstreamHost("127.0.0.1") .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build() })) .BDDfy(); @@ -215,7 +215,7 @@ namespace Ocelot.UnitTests.Configuration DownstreamScheme = "https", UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, } }, })) @@ -228,7 +228,7 @@ namespace Ocelot.UnitTests.Configuration .WithDownstreamScheme("https") .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build() })) .BDDfy(); @@ -248,7 +248,7 @@ namespace Ocelot.UnitTests.Configuration { UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = false, ServiceName = "ProductService" } @@ -270,7 +270,7 @@ namespace Ocelot.UnitTests.Configuration new ReRouteBuilder() .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder() .WithUseServiceDiscovery(true) .WithServiceDiscoveryProvider("consul") @@ -296,7 +296,7 @@ namespace Ocelot.UnitTests.Configuration { UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = false, } } @@ -309,7 +309,7 @@ namespace Ocelot.UnitTests.Configuration new ReRouteBuilder() .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder() .WithUseServiceDiscovery(false) .Build()) @@ -332,7 +332,7 @@ namespace Ocelot.UnitTests.Configuration { UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = false } } @@ -346,7 +346,7 @@ namespace Ocelot.UnitTests.Configuration new ReRouteBuilder() .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") .Build() })) @@ -367,7 +367,7 @@ namespace Ocelot.UnitTests.Configuration { UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true } }, @@ -385,7 +385,7 @@ namespace Ocelot.UnitTests.Configuration new ReRouteBuilder() .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithRequestIdKey("blahhhh") .Build() })) @@ -414,7 +414,7 @@ namespace Ocelot.UnitTests.Configuration new ReRouteBuilder() .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithAuthenticationOptions(authenticationOptions) .WithClaimsToHeaders(new List { @@ -431,7 +431,7 @@ namespace Ocelot.UnitTests.Configuration { UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, AuthenticationOptions = new FileAuthenticationOptions { @@ -482,7 +482,7 @@ namespace Ocelot.UnitTests.Configuration new ReRouteBuilder() .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithAuthenticationOptions(authenticationOptions) .Build() }; @@ -495,7 +495,7 @@ namespace Ocelot.UnitTests.Configuration { UpstreamPathTemplate = "/api/products/{productId}", DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, AuthenticationOptions = new FileAuthenticationOptions { diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index 1ef4cf6b..b65aa095 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -87,7 +87,7 @@ namespace Ocelot.UnitTests.Configuration { new ReRouteBuilder() .WithDownstreamPathTemplate(_downstreamTemplatePath) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build() }; diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index e7718f37..0b3aa149 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -66,7 +66,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("any old string") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 64c20af0..8514786d 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -45,7 +45,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("someUpstreamPath") .Build() }, string.Empty @@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build() ))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) @@ -78,7 +78,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("someUpstreamPath") .Build() }, string.Empty @@ -90,7 +90,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build() ))) .And(x => x.ThenTheUrlMatcherIsNotCalled()) @@ -110,13 +110,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("") .Build(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("Post") + .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamTemplatePattern("") .Build() }, string.Empty @@ -128,7 +128,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPathForAPost") - .WithUpstreamHttpMethod("Post") + .WithUpstreamHttpMethod(new List { "Post" }) .Build() ))) .BDDfy(); @@ -143,7 +143,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("somPath") .WithUpstreamPathTemplate("somePath") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("somePath") .Build(), }, string.Empty @@ -170,7 +170,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("Get, Post") + .WithUpstreamHttpMethod(new List { "Get", "Post" }) .WithUpstreamTemplatePattern("") .Build() }, string.Empty @@ -182,7 +182,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod("Post") + .WithUpstreamHttpMethod(new List { "Post" }) .Build() ))) .BDDfy(); @@ -201,7 +201,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("") + .WithUpstreamHttpMethod(new List()) .WithUpstreamTemplatePattern("") .Build() }, string.Empty @@ -213,7 +213,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod("Post") + .WithUpstreamHttpMethod(new List { "Post" }) .Build() ))) .BDDfy(); @@ -232,7 +232,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") - .WithUpstreamHttpMethod("Get, Patch, Delete") + .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" }) .WithUpstreamTemplatePattern("") .Build() }, string.Empty diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index aea1780f..ae322150 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -78,7 +78,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("any old string") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithDownstreamScheme("https") .Build()))) .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123")) diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 00445ee6..4939c901 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -29,7 +29,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer new DownstreamRoute( new List(), new ReRouteBuilder() - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) @@ -44,7 +44,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("/") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) @@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("api") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) @@ -70,7 +70,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("api/") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) @@ -83,7 +83,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamPathTemplate("api/product/products/") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) @@ -101,7 +101,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder() .WithDownstreamPathTemplate("productservice/products/{productId}/") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) @@ -119,7 +119,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder() .WithDownstreamPathTemplate("productservice/products/{productId}/variants") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) @@ -138,7 +138,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder() .WithDownstreamPathTemplate("productservice/products/{productId}/variants/{variantId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) @@ -158,7 +158,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder() .WithDownstreamPathTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) diff --git a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs index 95989688..395d7862 100644 --- a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.Headers { new ClaimToThing("UserId", "Subject", "", 0) }) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs index f8bf8f6c..ccf97772 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs @@ -4,6 +4,7 @@ using Ocelot.Configuration.Builder; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.ServiceDiscovery; using Shouldly; +using System.Collections.Generic; using TestStack.BDDfy; using Xunit; @@ -29,7 +30,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var reRoute = new ReRouteBuilder() .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build(); this.Given(x => x.GivenAReRoute(reRoute)) @@ -44,7 +45,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var reRoute = new ReRouteBuilder() .WithLoadBalancer("RoundRobin") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .Build(); @@ -60,7 +61,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var reRoute = new ReRouteBuilder() .WithLoadBalancer("LeastConnection") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .Build(); @@ -76,7 +77,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var reRoute = new ReRouteBuilder() .WithLoadBalancer("RoundRobin") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .Build(); diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index a7dfd1ac..65074b67 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -73,7 +73,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) @@ -90,7 +90,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) @@ -106,7 +106,7 @@ namespace Ocelot.UnitTests.LoadBalancer { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) diff --git a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs index 898563f7..1343df7d 100644 --- a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs @@ -74,7 +74,7 @@ namespace Ocelot.UnitTests.QueryStrings { new ClaimToThing("UserId", "Subject", "", 0) }) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) diff --git a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs index 81be28cc..a38d5a67 100644 --- a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs @@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.RateLimit var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions( new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List(), false, "", "", new Ocelot.Configuration.RateLimitRule("1s", 100, 3), 429)) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) @@ -89,7 +89,7 @@ namespace Ocelot.UnitTests.RateLimit var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions( new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List() { "ocelotclient2" }, false, "", "", new RateLimitRule( "1s", 100,3),429)) - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) diff --git a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs index 8cec477e..f8563abf 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs @@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.Request var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() .WithRequestIdKey("LSRequestId") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) diff --git a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs index 4521e315..d56bbce6 100644 --- a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs @@ -78,7 +78,7 @@ namespace Ocelot.UnitTests.RequestId new ReRouteBuilder() .WithDownstreamPathTemplate("any old string") .WithRequestIdKey("LSRequestId") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); var requestId = Guid.NewGuid().ToString(); @@ -97,7 +97,7 @@ namespace Ocelot.UnitTests.RequestId new ReRouteBuilder() .WithDownstreamPathTemplate("any old string") .WithRequestIdKey("LSRequestId") - .WithUpstreamHttpMethod("Get") + .WithUpstreamHttpMethod(new List { "Get" }) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) diff --git a/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs b/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs index f4beb0f1..082e7177 100644 --- a/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs @@ -4,6 +4,7 @@ using Ocelot.Configuration.Builder; using Ocelot.Logging; using Ocelot.Requester.QoS; using Shouldly; +using System.Collections.Generic; using TestStack.BDDfy; using Xunit; @@ -31,7 +32,7 @@ namespace Ocelot.UnitTests.Requester public void should_return_no_qos_provider() { var reRoute = new ReRouteBuilder() - .WithUpstreamHttpMethod("get") + .WithUpstreamHttpMethod(new List { "get" }) .WithIsQos(false) .Build(); @@ -51,7 +52,7 @@ namespace Ocelot.UnitTests.Requester .Build(); var reRoute = new ReRouteBuilder() - .WithUpstreamHttpMethod("get") + .WithUpstreamHttpMethod(new List { "get" }) .WithIsQos(true) .WithQosOptions(qosOptions) .Build(); From ac4902227434963718af789916647ede6640024a Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Tue, 9 May 2017 19:02:26 +0100 Subject: [PATCH 03/10] Updated CharactersDontMatch method. At this point the comparer must ignore case sensitive. --- .../UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs index 0859f4c0..8e5a2416 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs @@ -70,7 +70,7 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher private bool CharactersDontMatch(char characterOne, char characterTwo) { - return characterOne != characterTwo; + return char.ToLower(characterOne) != char.ToLower(characterTwo); } private bool ContinueScanningUrl(int counterForUrl, int urlLength) From f452e8ea86c893090d5a700fa109279891765171 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Wed, 10 May 2017 21:23:36 +0100 Subject: [PATCH 04/10] Fixes to get build running again on macOS. Basically, re-applying changes from #41 --- build.cake | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/build.cake b/build.cake index eddaffc0..184b1faa 100644 --- a/build.cake +++ b/build.cake @@ -92,7 +92,7 @@ Task("Version") if (AppVeyor.IsRunningOnAppVeyor) { Information("Persisting version number..."); - PersistVersion(nugetVersion); + PersistVersion(committedVersion, nugetVersion); buildVersion = nugetVersion; } else @@ -229,7 +229,7 @@ Task("CreatePackages") EnsureDirectoryExists(packagesDir); CopyFiles("./src/**/Ocelot.*.nupkg", packagesDir); - GenerateReleaseNotes(); + GenerateReleaseNotes(releaseNotesFile); System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", @@ -251,9 +251,9 @@ Task("ReleasePackagesToUnstableFeed") .IsDependentOn("CreatePackages") .Does(() => { - if (ShouldPublishToUnstableFeed()) + if (ShouldPublishToUnstableFeed(nugetFeedUnstableBranchFilter, versioning.BranchName)) { - PublishPackages(nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); + PublishPackages(packagesDir, artifactsFile, nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); } }); @@ -306,7 +306,7 @@ Task("ReleasePackagesToStableFeed") .IsDependentOn("DownloadGitHubReleaseArtifacts") .Does(() => { - PublishPackages(nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); + PublishPackages(packagesDir, artifactsFile, nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); }); Task("Release") @@ -326,9 +326,9 @@ private GitVersion GetNuGetVersionForCommit() } /// Updates project version in all of our projects -private void PersistVersion(string version) +private void PersistVersion(string committedVersion, string newVersion) { - Information(string.Format("We'll search all csproj files for {0} and replace with {1}...", committedVersion, version)); + Information(string.Format("We'll search all csproj files for {0} and replace with {1}...", committedVersion, newVersion)); var projectFiles = GetFiles("./**/*.csproj"); @@ -339,24 +339,30 @@ private void PersistVersion(string version) Information(string.Format("Updating {0}...", file)); var updatedProjectFile = System.IO.File.ReadAllText(file) - .Replace(committedVersion, version); + .Replace(committedVersion, newVersion); System.IO.File.WriteAllText(file, updatedProjectFile); } } /// generates release notes based on issues closed in GitHub since the last release -private void GenerateReleaseNotes() +private void GenerateReleaseNotes(ConvertableFilePath file) { - Information("Generating release notes at " + releaseNotesFile); + if(!IsRunningOnWindows()) + { + Warning("We are not running on Windows so we cannot generate release notes."); + return; + } + + Information("Generating release notes at " + file); var releaseNotesExitCode = StartProcess( @"tools/GitReleaseNotes/tools/gitreleasenotes.exe", - new ProcessSettings { Arguments = ". /o " + releaseNotesFile }); + new ProcessSettings { Arguments = ". /o " + file }); - if (string.IsNullOrEmpty(System.IO.File.ReadAllText(releaseNotesFile))) + if (string.IsNullOrEmpty(System.IO.File.ReadAllText(file))) { - System.IO.File.WriteAllText(releaseNotesFile, "No issues closed since last release"); + System.IO.File.WriteAllText(file, "No issues closed since last release"); } if (releaseNotesExitCode != 0) @@ -366,7 +372,7 @@ private void GenerateReleaseNotes() } /// Publishes code and symbols packages to nuget feed, based on contents of artifacts file -private void PublishPackages(string feedApiKey, string codeFeedUrl, string symbolFeedUrl) +private void PublishPackages(ConvertableDirectoryPath packagesDir, ConvertableFilePath artifactsFile, string feedApiKey, string codeFeedUrl, string symbolFeedUrl) { var artifacts = System.IO.File .ReadAllLines(artifactsFile) @@ -375,6 +381,8 @@ private void PublishPackages(string feedApiKey, string codeFeedUrl, string symbo var codePackage = packagesDir + File(artifacts["nuget"]); + Information("Pushing package " + codePackage); + NuGetPush( codePackage, new NuGetPushSettings { @@ -401,17 +409,17 @@ private string GetResource(string url) } } -private bool ShouldPublishToUnstableFeed() +private bool ShouldPublishToUnstableFeed(string filter, string branchName) { - var regex = new System.Text.RegularExpressions.Regex(nugetFeedUnstableBranchFilter); - var publish = regex.IsMatch(versioning.BranchName); + var regex = new System.Text.RegularExpressions.Regex(filter); + var publish = regex.IsMatch(branchName); if (publish) { - Information("Branch " + versioning.BranchName + " will be published to the unstable feed"); + Information("Branch " + branchName + " will be published to the unstable feed"); } else { - Information("Branch " + versioning.BranchName + " will not be published to the unstable feed"); + Information("Branch " + branchName + " will not be published to the unstable feed"); } return publish; } \ No newline at end of file From 30a5227e1e364d332cda865f478811ef211cb35f Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Wed, 17 May 2017 15:06:21 +0100 Subject: [PATCH 05/10] Adds two acceptance tests that checks two scenarios: - Get 401 when we do a request to api with a token issued to other api - Get 403 when we do a request to scope not allowed --- .../AuthenticationTests.cs | 138 +++++++++++++++--- test/Ocelot.AcceptanceTests/Steps.cs | 46 ++++++ 2 files changed, 167 insertions(+), 17 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 32e72a18..40ff7047 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -51,18 +51,18 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = new List { "Post" }, AuthenticationOptions = new FileAuthenticationOptions { - AllowedScopes = new List(), + AllowedScopes = new List(), Provider = "IdentityServer", ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, - ApiName = "api", + ApiName = "api", ApiSecret = "secret" } } } }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) @@ -89,18 +89,18 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = new List { "Post" }, AuthenticationOptions = new FileAuthenticationOptions { - AllowedScopes = new List(), + AllowedScopes = new List(), Provider = "IdentityServer", ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, - ApiName = "api", + ApiName = "api", ApiSecret = "secret" } } } }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference)) + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) @@ -127,18 +127,18 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = new List { "Get" }, AuthenticationOptions = new FileAuthenticationOptions { - AllowedScopes = new List(), + AllowedScopes = new List(), Provider = "IdentityServer", ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, - ApiName = "api", + ApiName = "api", ApiSecret = "secret" } } } }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) @@ -150,6 +150,84 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_401_using_identity_server_with_token_requested_for_other_api() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } + + [Fact] + public void should_return_response_403_using_identity_server_with_scope_not_allowed() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List{ "api", "openid", "offline_access" }, + Provider = "IdentityServer", + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + .BDDfy(); + } + [Fact] public void should_return_201_using_identity_server_access_token() { @@ -168,18 +246,18 @@ namespace Ocelot.AcceptanceTests AuthenticationOptions = new FileAuthenticationOptions { - AllowedScopes = new List(), + AllowedScopes = new List(), Provider = "IdentityServer", ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, - ApiName = "api", + ApiName = "api", ApiSecret = "secret" } } } }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) @@ -208,18 +286,18 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = new List { "Post" }, AuthenticationOptions = new FileAuthenticationOptions { - AllowedScopes = new List(), + AllowedScopes = new List(), Provider = "IdentityServer", ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, - ApiName = "api", + ApiName = "api", ApiSecret = "secret" } } } }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference)) + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) @@ -252,7 +330,7 @@ namespace Ocelot.AcceptanceTests _servicebuilder.Start(); } - private void GivenThereIsAnIdentityServerOn(string url, string apiName, AccessTokenType tokenType) + private void GivenThereIsAnIdentityServerOn(string url, string apiName, string api2Name, AccessTokenType tokenType) { _identityServerBuilder = new WebHostBuilder() .UseUrls(url) @@ -276,6 +354,32 @@ namespace Ocelot.AcceptanceTests Scopes = new List() { new Scope("api"), + new Scope("api.readOnly"), + new Scope("openid"), + new Scope("offline_access") + }, + ApiSecrets = new List() + { + new Secret + { + Value = "secret".Sha256() + } + }, + UserClaims = new List() + { + "CustomerId", "LocationId" + } + }, + new ApiResource + { + Name = api2Name, + Description = "My second API", + Enabled = true, + DisplayName = "second test", + Scopes = new List() + { + new Scope("api2"), + new Scope("api2.readOnly"), new Scope("openid"), new Scope("offline_access") }, @@ -299,7 +403,7 @@ namespace Ocelot.AcceptanceTests ClientId = "client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = new List {new Secret("secret".Sha256())}, - AllowedScopes = new List { apiName, "openid", "offline_access" }, + AllowedScopes = new List { apiName, api2Name, "api.readOnly", "openid", "offline_access" }, AccessTokenType = tokenType, Enabled = true, RequireClientSecret = false diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 79a586ac..cb408037 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -199,6 +199,52 @@ namespace Ocelot.AcceptanceTests } } + public void GivenIHaveATokenForApiReadOnlyScope(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "client"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "api.readOnly"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + using (var httpClient = new HttpClient()) + { + var response = httpClient.PostAsync(tokenUrl, content).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + response.EnsureSuccessStatusCode(); + _token = JsonConvert.DeserializeObject(responseContent); + } + } + + public void GivenIHaveATokenForApi2(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "client"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "api2"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + using (var httpClient = new HttpClient()) + { + var response = httpClient.PostAsync(tokenUrl, content).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + response.EnsureSuccessStatusCode(); + _token = JsonConvert.DeserializeObject(responseContent); + } + } + public void GivenIHaveAnOcelotToken(string adminPath) { var tokenUrl = $"{adminPath}/connect/token"; From 488aa973427a7c4eaec1f7d4e2541b2fb7119e7d Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Fri, 19 May 2017 11:41:38 +0100 Subject: [PATCH 06/10] Removed unnecessary IdentityServer4 nuget package. --- test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 06a30386..bce396d6 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -43,7 +43,6 @@ - From 7748262ecfc1473b16aa10d983c9110e2f25b956 Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Fri, 19 May 2017 11:49:35 +0100 Subject: [PATCH 07/10] Updated IdentityServer4.AccessTokenValidation package from 1.0.2 to 1.2.0. The removed version had a known issue with the audience check. --- src/Ocelot/Ocelot.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index 8fdb917d..d9ebf70e 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -40,7 +40,7 @@ - + From 07671b8fdb8b5c87f764fcf3328538dcb34a51f7 Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Fri, 19 May 2017 14:46:25 +0100 Subject: [PATCH 08/10] Updated all IdentityServer packages. --- src/Ocelot/Ocelot.csproj | 2 +- test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index d9ebf70e..162b80da 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -48,7 +48,7 @@ - + diff --git a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj index f2bb5354..a6432df0 100644 --- a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj @@ -44,7 +44,7 @@ - + From efa68e99492238d0c02e54219e352dc087be85b2 Mon Sep 17 00:00:00 2001 From: Juan Carlos Santana Herrera Date: Wed, 31 May 2017 18:27:28 +0100 Subject: [PATCH 09/10] Allowed scopes checking added to AuthorisationMiddleware. Acceptance tests added. --- src/Ocelot/Authorisation/ClaimsAuthoriser.cs | 2 +- .../{IAuthoriser.cs => IClaimsAuthoriser.cs} | 5 +- src/Ocelot/Authorisation/IScopesAuthoriser.cs | 12 +++ .../Middleware/AuthorisationMiddleware.cs | 54 +++++++++++-- .../Authorisation/ScopeNotAuthorisedError.cs | 12 +++ src/Ocelot/Authorisation/ScopesAuthoriser.cs | 51 ++++++++++++ .../ServiceCollectionExtensions.cs | 3 +- src/Ocelot/Errors/OcelotErrorCode.cs | 1 + .../Claims/Parser/ClaimsParser.cs | 15 +++- .../Claims/Parser/IClaimsParser.cs | 1 + .../Responder/ErrorsToHttpStatusCodeMapper.cs | 1 + .../AuthenticationTests.cs | 39 --------- .../AuthorisationTests.cs | 81 ++++++++++++++++++- .../ClaimsToHeadersForwardingTests.cs | 2 +- .../ClaimsToQueryStringForwardingTests.cs | 2 +- .../AuthorisationMiddlewareTests.cs | 7 +- 16 files changed, 232 insertions(+), 56 deletions(-) rename src/Ocelot/Authorisation/{IAuthoriser.cs => IClaimsAuthoriser.cs} (67%) create mode 100644 src/Ocelot/Authorisation/IScopesAuthoriser.cs create mode 100644 src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs create mode 100644 src/Ocelot/Authorisation/ScopesAuthoriser.cs diff --git a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs index 96f7acd6..13c18bb3 100644 --- a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs +++ b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs @@ -7,7 +7,7 @@ namespace Ocelot.Authorisation { using Infrastructure.Claims.Parser; - public class ClaimsAuthoriser : IAuthoriser + public class ClaimsAuthoriser : IClaimsAuthoriser { private readonly IClaimsParser _claimsParser; diff --git a/src/Ocelot/Authorisation/IAuthoriser.cs b/src/Ocelot/Authorisation/IClaimsAuthoriser.cs similarity index 67% rename from src/Ocelot/Authorisation/IAuthoriser.cs rename to src/Ocelot/Authorisation/IClaimsAuthoriser.cs index 08a7307f..0288403a 100644 --- a/src/Ocelot/Authorisation/IAuthoriser.cs +++ b/src/Ocelot/Authorisation/IClaimsAuthoriser.cs @@ -5,9 +5,8 @@ namespace Ocelot.Authorisation { using System.Collections.Generic; - public interface IAuthoriser + public interface IClaimsAuthoriser { - Response Authorise(ClaimsPrincipal claimsPrincipal, - Dictionary routeClaimsRequirement); + Response Authorise(ClaimsPrincipal claimsPrincipal, Dictionary routeClaimsRequirement); } } diff --git a/src/Ocelot/Authorisation/IScopesAuthoriser.cs b/src/Ocelot/Authorisation/IScopesAuthoriser.cs new file mode 100644 index 00000000..62b7bf93 --- /dev/null +++ b/src/Ocelot/Authorisation/IScopesAuthoriser.cs @@ -0,0 +1,12 @@ +using System.Security.Claims; +using Ocelot.Responses; + +namespace Ocelot.Authorisation +{ + using System.Collections.Generic; + + public interface IScopesAuthoriser + { + Response Authorise(ClaimsPrincipal claimsPrincipal, List routeAllowedScopes); + } +} diff --git a/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs index a86643a4..bfcd5f8d 100644 --- a/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs +++ b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs @@ -1,6 +1,7 @@ using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; +using Ocelot.Configuration; namespace Ocelot.Authorisation.Middleware { @@ -13,17 +14,20 @@ namespace Ocelot.Authorisation.Middleware public class AuthorisationMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; - private readonly IAuthoriser _authoriser; + private readonly IClaimsAuthoriser _claimsAuthoriser; + private readonly IScopesAuthoriser _scopesAuthoriser; private readonly IOcelotLogger _logger; public AuthorisationMiddleware(RequestDelegate next, IRequestScopedDataRepository requestScopedDataRepository, - IAuthoriser authoriser, + IClaimsAuthoriser claimsAuthoriser, + IScopesAuthoriser scopesAuthoriser, IOcelotLoggerFactory loggerFactory) : base(requestScopedDataRepository) { _next = next; - _authoriser = authoriser; + _claimsAuthoriser = claimsAuthoriser; + _scopesAuthoriser = scopesAuthoriser; _logger = loggerFactory.CreateLogger(); } @@ -31,11 +35,41 @@ namespace Ocelot.Authorisation.Middleware { _logger.LogDebug("started authorisation"); - if (DownstreamRoute.ReRoute.IsAuthorised) + if (IsAuthenticatedRoute(DownstreamRoute.ReRoute)) + { + _logger.LogDebug("route is authenticated scopes must be checked"); + + var authorised = _scopesAuthoriser.Authorise(context.User, DownstreamRoute.ReRoute.AuthenticationOptions.AllowedScopes); + + if (authorised.IsError) + { + _logger.LogDebug("error authorising user scopes"); + + SetPipelineError(authorised.Errors); + return; + } + + if (IsAuthorised(authorised)) + { + _logger.LogDebug("user scopes is authorised calling next authorisation checks"); + } + else + { + _logger.LogDebug("user scopes is not authorised setting pipeline error"); + + SetPipelineError(new List + { + new UnauthorisedError( + $"{context.User.Identity.Name} unable to access {DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}") + }); + } + } + + if (IsAuthorisedRoute(DownstreamRoute.ReRoute)) { _logger.LogDebug("route is authorised"); - var authorised = _authoriser.Authorise(context.User, DownstreamRoute.ReRoute.RouteClaimsRequirement); + var authorised = _claimsAuthoriser.Authorise(context.User, DownstreamRoute.ReRoute.RouteClaimsRequirement); if (authorised.IsError) { @@ -78,5 +112,15 @@ namespace Ocelot.Authorisation.Middleware { return authorised.Data; } + + private static bool IsAuthenticatedRoute(ReRoute reRoute) + { + return reRoute.IsAuthenticated; + } + + private static bool IsAuthorisedRoute(ReRoute reRoute) + { + return reRoute.IsAuthorised; + } } } diff --git a/src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs b/src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs new file mode 100644 index 00000000..5460cb90 --- /dev/null +++ b/src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.Authorisation +{ + public class ScopeNotAuthorisedError : Error + { + public ScopeNotAuthorisedError(string message) + : base(message, OcelotErrorCode.ScopeNotAuthorisedError) + { + } + } +} diff --git a/src/Ocelot/Authorisation/ScopesAuthoriser.cs b/src/Ocelot/Authorisation/ScopesAuthoriser.cs new file mode 100644 index 00000000..6f32d6c3 --- /dev/null +++ b/src/Ocelot/Authorisation/ScopesAuthoriser.cs @@ -0,0 +1,51 @@ +using IdentityModel; +using Ocelot.Errors; +using Ocelot.Responses; +using System.Collections.Generic; +using System.Security.Claims; +using System.Linq; + +namespace Ocelot.Authorisation +{ + using Infrastructure.Claims.Parser; + + public class ScopesAuthoriser : IScopesAuthoriser + { + private readonly IClaimsParser _claimsParser; + + public ScopesAuthoriser(IClaimsParser claimsParser) + { + _claimsParser = claimsParser; + } + + public Response Authorise(ClaimsPrincipal claimsPrincipal, List routeAllowedScopes) + { + if (routeAllowedScopes == null || routeAllowedScopes.Count == 0) + { + return new OkResponse(true); + } + + var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, JwtClaimTypes.Scope); + + if (values.IsError) + { + return new ErrorResponse(values.Errors); + } + + var userScopes = values.Data; + + List matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList(); + + if (matchesScopes == null || matchesScopes.Count == 0) + { + return new ErrorResponse(new List + { + new ScopeNotAuthorisedError( + $"no one user scope: '{string.Join(",", userScopes)}' match with some allowed scope: '{string.Join(",", routeAllowedScopes)}'") + }); + } + + return new OkResponse(true); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index ef022923..d52341fe 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -144,7 +144,8 @@ namespace Ocelot.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/src/Ocelot/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs index de7960c4..cf191e63 100644 --- a/src/Ocelot/Errors/OcelotErrorCode.cs +++ b/src/Ocelot/Errors/OcelotErrorCode.cs @@ -17,6 +17,7 @@ InstructionNotForClaimsError, UnauthorizedError, ClaimValueNotAuthorisedError, + ScopeNotAuthorisedError, UserDoesNotHaveClaimError, DownstreamPathTemplateContainsSchemeError, DownstreamPathNullOrEmptyError, diff --git a/src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs b/src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs index e37f48fa..f5f3e3b4 100644 --- a/src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs +++ b/src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs @@ -1,10 +1,10 @@ namespace Ocelot.Infrastructure.Claims.Parser { + using Errors; + using Responses; using System.Collections.Generic; using System.Linq; using System.Security.Claims; - using Errors; - using Responses; public class ClaimsParser : IClaimsParser { @@ -37,6 +37,17 @@ return new OkResponse(value); } + + public Response> GetValuesByClaimType(IEnumerable claims, string claimType) + { + List values = new List(); + + values.AddRange(claims.Where(x => x.Type == claimType).Select(x => x.Value).ToList()); + + return new OkResponse>(values); + } + + private Response GetValue(IEnumerable claims, string key) { var claim = claims.FirstOrDefault(c => c.Type == key); diff --git a/src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs b/src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs index fa94cd22..1f6e65d3 100644 --- a/src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs +++ b/src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs @@ -7,5 +7,6 @@ public interface IClaimsParser { Response GetValue(IEnumerable claims, string key, string delimiter, int index); + Response> GetValuesByClaimType(IEnumerable claims, string claimType); } } \ No newline at end of file diff --git a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs index 5c1e9fd0..be7c59b9 100644 --- a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs +++ b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -15,6 +15,7 @@ namespace Ocelot.Responder if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError || e.Code == OcelotErrorCode.ClaimValueNotAuthorisedError + || e.Code == OcelotErrorCode.ScopeNotAuthorisedError || e.Code == OcelotErrorCode.UserDoesNotHaveClaimError || e.Code == OcelotErrorCode.CannotFindClaimError)) { diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 40ff7047..c0d143b9 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -189,45 +189,6 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } - [Fact] - public void should_return_response_403_using_identity_server_with_scope_not_allowed() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List{ "api", "openid", "offline_access" }, - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; - - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope(_identityServerRootUrl)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) - .BDDfy(); - } - [Fact] public void should_return_201_using_identity_server_access_token() { diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 2e4a446e..011bb679 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -140,6 +140,84 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200_using_identity_server_with_allowed_scope() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamHost = "localhost", + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List{ "api", "api.readOnly", "openid", "offline_access" }, + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + [Fact] + public void should_return_response_403_using_identity_server_with_scope_not_allowed() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamHost = "localhost", + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List{ "api", "openid", "offline_access" }, + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + .BDDfy(); + } + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _servicebuilder = new WebHostBuilder() @@ -185,6 +263,7 @@ namespace Ocelot.AcceptanceTests Scopes = new List() { new Scope("api"), + new Scope("api.readOnly"), new Scope("openid"), new Scope("offline_access") }, @@ -209,7 +288,7 @@ namespace Ocelot.AcceptanceTests ClientId = "client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = new List {new Secret("secret".Sha256())}, - AllowedScopes = new List { apiName, "openid", "offline_access" }, + AllowedScopes = new List { apiName, "api.readOnly", "openid", "offline_access" }, AccessTokenType = tokenType, Enabled = true, RequireClientSecret = false diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index c2caa19e..88a294a0 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -61,7 +61,7 @@ namespace Ocelot.AcceptanceTests { AllowedScopes = new List { - "openid", "offline_access" + "openid", "offline_access", "api" }, Provider = "IdentityServer", ProviderRootUrl = "http://localhost:52888", diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index f2f1ca66..a6162c5f 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -61,7 +61,7 @@ namespace Ocelot.AcceptanceTests { AllowedScopes = new List { - "openid", "offline_access" + "openid", "offline_access", "api" }, Provider = "IdentityServer", ProviderRootUrl = "http://localhost:57888", diff --git a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs index 9a890089..9bf15b42 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs @@ -25,7 +25,8 @@ namespace Ocelot.UnitTests.Authorization public class AuthorisationMiddlewareTests : IDisposable { private readonly Mock _scopedRepository; - private readonly Mock _authService; + private readonly Mock _authService; + private readonly Mock _authScopesService; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; @@ -36,7 +37,8 @@ namespace Ocelot.UnitTests.Authorization { _url = "http://localhost:51879"; _scopedRepository = new Mock(); - _authService = new Mock(); + _authService = new Mock(); + _authScopesService = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => @@ -44,6 +46,7 @@ namespace Ocelot.UnitTests.Authorization x.AddSingleton(); x.AddLogging(); x.AddSingleton(_authService.Object); + x.AddSingleton(_authScopesService.Object); x.AddSingleton(_scopedRepository.Object); }) .UseUrls(_url) From 6c1b95f95ba9926cf6f6fb83a5f7c4ce609bb0be Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 10 Jun 2017 15:52:31 +0100 Subject: [PATCH 10/10] fixed some broken tests due to recent merges! --- .../Creator/FileOcelotConfigurationCreator.cs | 378 +++++++++--------- .../Requester/HttpClientHttpRequester.cs | 21 +- test/Ocelot.AcceptanceTests/QoSTests.cs | 3 +- 3 files changed, 206 insertions(+), 196 deletions(-) diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index a2ebb709..c44edd08 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -1,191 +1,191 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Ocelot.Configuration.Builder; -using Ocelot.Configuration.File; -using Ocelot.Configuration.Parser; -using Ocelot.Configuration.Validator; -using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.Logging; -using Ocelot.Requester.QoS; -using Ocelot.Responses; -using Ocelot.Utilities; - -namespace Ocelot.Configuration.Creator -{ - /// - /// Register as singleton - /// - public class FileOcelotConfigurationCreator : IOcelotConfigurationCreator - { - private readonly IOptions _options; - private readonly IConfigurationValidator _configurationValidator; - private readonly IOcelotLogger _logger; - private readonly ILoadBalancerFactory _loadBalanceFactory; - private readonly ILoadBalancerHouse _loadBalancerHouse; - private readonly IQoSProviderFactory _qoSProviderFactory; - private readonly IQosProviderHouse _qosProviderHouse; - private readonly IClaimsToThingCreator _claimsToThingCreator; - private readonly IAuthenticationOptionsCreator _authOptionsCreator; - private IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator; - private IRequestIdKeyCreator _requestIdKeyCreator; - private IServiceProviderConfigurationCreator _serviceProviderConfigCreator; - private IQoSOptionsCreator _qosOptionsCreator; - private IReRouteOptionsCreator _fileReRouteOptionsCreator; - private IRateLimitOptionsCreator _rateLimitOptionsCreator; - - public FileOcelotConfigurationCreator( - IOptions options, +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Ocelot.Configuration.Builder; +using Ocelot.Configuration.File; +using Ocelot.Configuration.Parser; +using Ocelot.Configuration.Validator; +using Ocelot.LoadBalancer.LoadBalancers; +using Ocelot.Logging; +using Ocelot.Requester.QoS; +using Ocelot.Responses; +using Ocelot.Utilities; + +namespace Ocelot.Configuration.Creator +{ + /// + /// Register as singleton + /// + public class FileOcelotConfigurationCreator : IOcelotConfigurationCreator + { + private readonly IOptions _options; + private readonly IConfigurationValidator _configurationValidator; + private readonly IOcelotLogger _logger; + private readonly ILoadBalancerFactory _loadBalanceFactory; + private readonly ILoadBalancerHouse _loadBalancerHouse; + private readonly IQoSProviderFactory _qoSProviderFactory; + private readonly IQosProviderHouse _qosProviderHouse; + private readonly IClaimsToThingCreator _claimsToThingCreator; + private readonly IAuthenticationOptionsCreator _authOptionsCreator; + private IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator; + private IRequestIdKeyCreator _requestIdKeyCreator; + private IServiceProviderConfigurationCreator _serviceProviderConfigCreator; + private IQoSOptionsCreator _qosOptionsCreator; + private IReRouteOptionsCreator _fileReRouteOptionsCreator; + private IRateLimitOptionsCreator _rateLimitOptionsCreator; + + public FileOcelotConfigurationCreator( + IOptions options, IConfigurationValidator configurationValidator, - IOcelotLoggerFactory loggerFactory, - ILoadBalancerFactory loadBalancerFactory, - ILoadBalancerHouse loadBalancerHouse, - IQoSProviderFactory qoSProviderFactory, - IQosProviderHouse qosProviderHouse, - IClaimsToThingCreator claimsToThingCreator, - IAuthenticationOptionsCreator authOptionsCreator, - IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator, - IRequestIdKeyCreator requestIdKeyCreator, - IServiceProviderConfigurationCreator serviceProviderConfigCreator, - IQoSOptionsCreator qosOptionsCreator, - IReRouteOptionsCreator fileReRouteOptionsCreator, - IRateLimitOptionsCreator rateLimitOptionsCreator - ) - { - _rateLimitOptionsCreator = rateLimitOptionsCreator; - _requestIdKeyCreator = requestIdKeyCreator; - _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; - _authOptionsCreator = authOptionsCreator; - _loadBalanceFactory = loadBalancerFactory; - _loadBalancerHouse = loadBalancerHouse; - _qoSProviderFactory = qoSProviderFactory; - _qosProviderHouse = qosProviderHouse; - _options = options; - _configurationValidator = configurationValidator; - _logger = loggerFactory.CreateLogger(); - _claimsToThingCreator = claimsToThingCreator; - _serviceProviderConfigCreator = serviceProviderConfigCreator; - _qosOptionsCreator = qosOptionsCreator; - _fileReRouteOptionsCreator = fileReRouteOptionsCreator; - } - - public async Task> Create() - { - var config = await SetUpConfiguration(_options.Value); - - return new OkResponse(config); - } - - public async Task> Create(FileConfiguration fileConfiguration) - { - var config = await SetUpConfiguration(fileConfiguration); - - return new OkResponse(config); - } - - private async Task SetUpConfiguration(FileConfiguration fileConfiguration) - { - var response = _configurationValidator.IsValid(fileConfiguration); - - if (response.Data.IsError) - { - var errorBuilder = new StringBuilder(); - - foreach (var error in response.Errors) - { - errorBuilder.AppendLine(error.Message); - } - - throw new Exception($"Unable to start Ocelot..configuration, errors were {errorBuilder}"); - } - - var reRoutes = new List(); - - foreach (var reRoute in fileConfiguration.ReRoutes) - { - var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); - reRoutes.Add(ocelotReRoute); - } - - return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath); - } - - private async Task SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) - { - var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute); - - var requestIdKey = _requestIdKeyCreator.Create(fileReRoute, globalConfiguration); - - var reRouteKey = CreateReRouteKey(fileReRoute); - - var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute); - - var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration); - - var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute); - - var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest); - - var claimsToClaims = _claimsToThingCreator.Create(fileReRoute.AddClaimsToRequest); - - var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest); - - var qosOptions = _qosOptionsCreator.Create(fileReRoute); - - var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting); - - var reRoute = new ReRouteBuilder() - .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate) - .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate) - .WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod) - .WithUpstreamTemplatePattern(upstreamTemplatePattern) - .WithIsAuthenticated(fileReRouteOptions.IsAuthenticated) - .WithAuthenticationOptions(authOptionsForRoute) - .WithClaimsToHeaders(claimsToHeaders) - .WithClaimsToClaims(claimsToClaims) - .WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement) - .WithIsAuthorised(fileReRouteOptions.IsAuthorised) - .WithClaimsToQueries(claimsToQueries) - .WithRequestIdKey(requestIdKey) - .WithIsCached(fileReRouteOptions.IsCached) - .WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)) - .WithDownstreamScheme(fileReRoute.DownstreamScheme) - .WithLoadBalancer(fileReRoute.LoadBalancer) - .WithDownstreamHost(fileReRoute.DownstreamHost) - .WithDownstreamPort(fileReRoute.DownstreamPort) - .WithLoadBalancerKey(reRouteKey) - .WithServiceProviderConfiguraion(serviceProviderConfiguration) - .WithIsQos(fileReRouteOptions.IsQos) - .WithQosOptions(qosOptions) - .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) - .WithRateLimitOptions(rateLimitOption) - .Build(); - - await SetupLoadBalancer(reRoute); - SetupQosProvider(reRoute); - return reRoute; - } - - private string CreateReRouteKey(FileReRoute fileReRoute) - { - //note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain - var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}{fileReRoute.UpstreamHttpMethod}"; - return loadBalancerKey; - } - - private async Task SetupLoadBalancer(ReRoute reRoute) - { - var loadBalancer = await _loadBalanceFactory.Get(reRoute); - _loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer); - } - - private void SetupQosProvider(ReRoute reRoute) - { - var loadBalancer = _qoSProviderFactory.Get(reRoute); - _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer); - } - } + IOcelotLoggerFactory loggerFactory, + ILoadBalancerFactory loadBalancerFactory, + ILoadBalancerHouse loadBalancerHouse, + IQoSProviderFactory qoSProviderFactory, + IQosProviderHouse qosProviderHouse, + IClaimsToThingCreator claimsToThingCreator, + IAuthenticationOptionsCreator authOptionsCreator, + IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator, + IRequestIdKeyCreator requestIdKeyCreator, + IServiceProviderConfigurationCreator serviceProviderConfigCreator, + IQoSOptionsCreator qosOptionsCreator, + IReRouteOptionsCreator fileReRouteOptionsCreator, + IRateLimitOptionsCreator rateLimitOptionsCreator + ) + { + _rateLimitOptionsCreator = rateLimitOptionsCreator; + _requestIdKeyCreator = requestIdKeyCreator; + _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; + _authOptionsCreator = authOptionsCreator; + _loadBalanceFactory = loadBalancerFactory; + _loadBalancerHouse = loadBalancerHouse; + _qoSProviderFactory = qoSProviderFactory; + _qosProviderHouse = qosProviderHouse; + _options = options; + _configurationValidator = configurationValidator; + _logger = loggerFactory.CreateLogger(); + _claimsToThingCreator = claimsToThingCreator; + _serviceProviderConfigCreator = serviceProviderConfigCreator; + _qosOptionsCreator = qosOptionsCreator; + _fileReRouteOptionsCreator = fileReRouteOptionsCreator; + } + + public async Task> Create() + { + var config = await SetUpConfiguration(_options.Value); + + return new OkResponse(config); + } + + public async Task> Create(FileConfiguration fileConfiguration) + { + var config = await SetUpConfiguration(fileConfiguration); + + return new OkResponse(config); + } + + private async Task SetUpConfiguration(FileConfiguration fileConfiguration) + { + var response = _configurationValidator.IsValid(fileConfiguration); + + if (response.Data.IsError) + { + var errorBuilder = new StringBuilder(); + + foreach (var error in response.Errors) + { + errorBuilder.AppendLine(error.Message); + } + + throw new Exception($"Unable to start Ocelot..configuration, errors were {errorBuilder}"); + } + + var reRoutes = new List(); + + foreach (var reRoute in fileConfiguration.ReRoutes) + { + var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); + reRoutes.Add(ocelotReRoute); + } + + return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath); + } + + private async Task SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) + { + var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute); + + var requestIdKey = _requestIdKeyCreator.Create(fileReRoute, globalConfiguration); + + var reRouteKey = CreateReRouteKey(fileReRoute); + + var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute); + + var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration); + + var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute); + + var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest); + + var claimsToClaims = _claimsToThingCreator.Create(fileReRoute.AddClaimsToRequest); + + var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest); + + var qosOptions = _qosOptionsCreator.Create(fileReRoute); + + var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting); + + var reRoute = new ReRouteBuilder() + .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate) + .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate) + .WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod) + .WithUpstreamTemplatePattern(upstreamTemplatePattern) + .WithIsAuthenticated(fileReRouteOptions.IsAuthenticated) + .WithAuthenticationOptions(authOptionsForRoute) + .WithClaimsToHeaders(claimsToHeaders) + .WithClaimsToClaims(claimsToClaims) + .WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement) + .WithIsAuthorised(fileReRouteOptions.IsAuthorised) + .WithClaimsToQueries(claimsToQueries) + .WithRequestIdKey(requestIdKey) + .WithIsCached(fileReRouteOptions.IsCached) + .WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)) + .WithDownstreamScheme(fileReRoute.DownstreamScheme) + .WithLoadBalancer(fileReRoute.LoadBalancer) + .WithDownstreamHost(fileReRoute.DownstreamHost) + .WithDownstreamPort(fileReRoute.DownstreamPort) + .WithLoadBalancerKey(reRouteKey) + .WithServiceProviderConfiguraion(serviceProviderConfiguration) + .WithIsQos(fileReRouteOptions.IsQos) + .WithQosOptions(qosOptions) + .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) + .WithRateLimitOptions(rateLimitOption) + .Build(); + + await SetupLoadBalancer(reRoute); + SetupQosProvider(reRoute); + return reRoute; + } + + private string CreateReRouteKey(FileReRoute fileReRoute) + { + //note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain + var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}{fileReRoute.UpstreamHttpMethod}"; + return loadBalancerKey; + } + + private async Task SetupLoadBalancer(ReRoute reRoute) + { + var loadBalancer = await _loadBalanceFactory.Get(reRoute); + _loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer); + } + + private void SetupQosProvider(ReRoute reRoute) + { + var loadBalancer = _qoSProviderFactory.Get(reRoute); + _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer); + } + } } \ No newline at end of file diff --git a/src/Ocelot/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs index a7f747d4..3f85af0c 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -22,9 +22,12 @@ namespace Ocelot.Requester public async Task> GetResponse(Request.Request request) { - var cacheKey = GetCacheKey(request); + var builder = new HttpClientBuilder(); + + var cacheKey = GetCacheKey(request, builder); + + var httpClient = GetHttpClient(cacheKey, builder); - IHttpClient httpClient = GetHttpClient(cacheKey); try { var response = await httpClient.SendAsync(request.HttpRequestMessage); @@ -51,11 +54,10 @@ namespace Ocelot.Requester } - private IHttpClient GetHttpClient(string cacheKey) + private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder) { - var builder = new HttpClientBuilder(); - var httpClient = _cacheHandlers.Get(cacheKey); + if (httpClient == null) { httpClient = builder.Create(); @@ -63,9 +65,16 @@ namespace Ocelot.Requester return httpClient; } - private string GetCacheKey(Request.Request request) + private string GetCacheKey(Request.Request request, IHttpClientBuilder builder) { string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}"; + + if (request.IsQos) + { + builder.WithQos(request.QosProvider, _logger); + baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}"; + } + return baseUrl; } } diff --git a/test/Ocelot.AcceptanceTests/QoSTests.cs b/test/Ocelot.AcceptanceTests/QoSTests.cs index 98c0540e..8825b75b 100644 --- a/test/Ocelot.AcceptanceTests/QoSTests.cs +++ b/test/Ocelot.AcceptanceTests/QoSTests.cs @@ -45,7 +45,8 @@ namespace Ocelot.AcceptanceTests ExceptionsAllowedBeforeBreaking = 1, TimeoutValue = 500, DurationOfBreak = 1000 - } + }, + } } };